题目

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);
}