题目
Description
有一个长度为 n 的序列 a1 ,a2 ···an ,ai 为在 [li ,ri ] 中独立均匀随机生成的实数。
若 1 ≤ i < j ≤ n 且 ai > aj ,我们称 (i,j) 为一个逆序对。你需要求出这个序列逆序对个数的期望值。为了简单起见,你只需要求出这个期望值对 998244353 取模的值。
Input
一行一个正整数 n。
接下来 n 行,第 i 行两个非负整数 li ,ri 。
Output
输出逆序对个数期望值对 998244353 取模的值。
Sample Input
3
2 3
4 5
1 6
Sample Output
1
Data Constraint
对于所有数据,0 ≤ li < ri ≤ 10^8 。
Subtask 1(20pts):n ≤ 3,ri ≤ 5。
Subtask 2(20pts):n ≤ 10。
Subtask 3(20pts):n ≤ 1000。
Subtask 4(20pts):n ≤ 10^5 ,li = 0。
Subtask 5(20pts):n ≤ 10^5 。
思路
使用线段树,维护每一个位置上期望有多少个数
顺着进行询问,如果在[a,a+1)相当于询问>a的位置之和+a位置的数/2,就相当于a[x]带一个权x,简单维护即可。
代码
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=5e6+77,mod=998244353;
int n,tl[M],tr[M],cnt,u;
ll ans,t[M][3],_2,l,r;
ll power(ll x,ll t)
{
ll b=1;
while(t)
{
if(t&1) b=b*x%mod;
x=x*x%mod; t>>=1;
}
return b;
}
ll s0,s1,s2;
void find(int x,int l,int r,int p)
{
if(x) s0+=t[x][0],s1+=t[x][1],s2+=t[x][2];
if(!x||l==r) return;
int mid=(l+r)>>1;
if(p<=mid) find(tl[x],l,mid,p);
else find(tr[x],mid+1,r,p);
}
void ins(int &x,int l,int r,int L,int R,ll a0,ll a1,ll a2)
{
if(l>R||r<L) return;
if(!x) x=++cnt;
if(L<=l&&r<=R)
{
t[x][0]+=a0,t[x][1]+=a1,t[x][2]+=a2;
return;
}
int mid=(l+r)>>1;
ins(tl[x],l,mid,L,R,a0,a1,a2);
ins(tr[x],mid+1,r,L,R,a0,a1,a2);
}
int main()
{
freopen("rng.in","r",stdin); freopen("rng.out","w",stdout);
scanf("%d",&n);
_2=power(2,mod-2),u=cnt=1;
while(n--)
{
scanf("%lld%lld",&l,&r); int d=r-l; ll invd=power(d,mod-2);
s0=s1=s2=0,find(1,0,1e8,r);
ans+=(s0%mod+s1%mod*r%mod+s2%mod*r%mod*r%mod)*invd%mod;
s0=s1=s2=0,find(1,0,1e8,l);
ans-=(s0%mod+s1%mod*l%mod+s2%mod*l%mod*l%mod)*invd%mod;
ins(u,0,1e8,1,l,0,1,0);
ins(u,0,1e8,l+1,r,-l*l%mod*_2%mod*invd%mod,l*invd%mod+1,-_2*invd%mod);
ins(u,0,1e8,r+1,1e8,(l+r)*_2%mod,0,0);
}
printf("%lld",(ans%mod+mod)%mod);
}