0%

「2020冬令营提高组」rng

题目链接

题意

长度为 nn 的序列 aa 满足 aia_i[li,ri][l_i,r_i] 中随机一实数,求该序列逆序对个数的期望值。

思路

发现每个 aia_i 对答案的贡献即为 j=i+1nai>aj\sum_{j=i+1}^na_i>a_j

从后往前考虑:

由于在实数范围内,整数边界不予考虑。

cic_i(i1,i](i-1,i] 中目前出现实数的期望个数,si,js_{i,j}k=ijck\sum_{k=i}^jc_ksi,js^\prime_{i,j}k=ijkck\sum_{k=i}^jk\cdot c_k

查询

假设 li=2,ri=5l_i=2,r_i=5res2,5res_{2,5} 即为 c0+c1+c2+52c3+32c4+12c53c_0+c_1+c_2+\frac{\frac52c_3+\frac32c_4+\frac12c_5}3

如何优化?

res2,5=s0,2+112(c3+c4+c5)(3c3+4c4+5c5)52=s0,2+(5+12)s3,5s3,552\begin{aligned} res_{2,5}&=s_{0,2}+\frac{\frac{11}2(c_3+c_4+c_5)-(3c_3+4c_4+5c_5)}{5-2}\\ &=s_{0,2}+\frac{(5+\frac12)s_{3,5}-s^\prime_{3,5}}{5-2} \end{aligned}

由此推出查询公式:

resl,r=s0,l+(r+12)sl+1,rsl+1,rrl=rs0,lls0,l+rsl+1,r+12sl+1,rsl+1,rrl=(r+12)s0,r(l+12)s0,l+s0,ls0,rrl\begin{aligned} res_{l,r}&=s_{0,l}+\frac{(r+\frac12)s_{l+1,r}-s^\prime_{l+1,r}}{r-l}\\ &=\frac{r*s_{0,l}-l*s_{0,l}+r*s_{l+1,r}+\frac12s_{l+1,r}-s^\prime_{l+1,r}}{r-l}\\ &=\frac{(r+\frac12)s_{0,r}-(l+\frac12)s_{0,l}+s^\prime_{0,l}-s^\prime_{0,r}}{r-l} \end{aligned}

修改

每次计算完 aia_i 对答案的贡献,就要用 aia_i 更新 ssss^\prime 数组。

区间 [li,ri][l_i,r_i]cc 数组的贡献为:

对于每个 li<jril_i<j\leq r_icjcj+1rilic_j\gets c_j+\frac1{r_i-l_i} 即可。

实现

不难看出,s,ss,s^\prime 数组需要维护区间和与区间修改,用线段树维护。

li,ril_i,r_i 较大,需要离散化。

在离散化+线段树中,维护 [l,r][l,r] 的线段树实际维护范围为 (pl1,pr](p_{l-1},p_r](其中 pp 为映射)。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
const int mod=998244353;
const long long inv2=(mod+1)>>1;
int n,siz,p[300001];
map<int,int>m;
long long ans;
struct number {
int l,r,ll;
int ml,mr,mll;
}a[100001];
struct seg_tree {
int l,r;
long long val,tag;
}t1[1200001],t2[1200001];
void make_map()
{
for(int i=1,j=0;i<=n;++i) {
p[++j]=a[i].l,p[++j]=a[i].r,p[++j]=a[i].ll;
}
sort(p+1,p+siz+1);
for(int i=1,j=0;i<=siz;++i) {
if(p[i]!=p[i-1])
{
m[p[i]]=++j;
p[j]=p[i];
}
}
for(int i=1;i<=n;++i) {
a[i].ml=m[a[i].l],a[i].mr=m[a[i].r],a[i].mll=m[a[i].ll];
}
return;
}
void build1(int num,int l,int r)
{
t1[num]=seg_tree{l,r,0,0};
if(l==r) {
return;
}
int mid=(l+r)>>1;
build1(num<<1,l,mid),build1(num<<1|1,mid+1,r);
return;
}
void build2(int num,int l,int r)
{
t2[num]=seg_tree{l,r,0,0};
if(l==r) {
return;
}
int mid=(l+r)>>1;
build2(num<<1,l,mid),build2(num<<1|1,mid+1,r);
return;
}
void push_down1(int num)
{
if(!t1[num].tag) {
return;
}
t1[num<<1].val=(t1[num<<1].val+t1[num].tag*(p[t1[num<<1].r]-p[t1[num<<1].l-1])%mod)%mod;
t1[num<<1].tag=(t1[num<<1].tag+t1[num].tag)%mod;
t1[num<<1|1].val=(t1[num<<1|1].val+t1[num].tag*(p[t1[num<<1|1].r]-p[t1[num<<1|1].l-1])%mod)%mod;
t1[num<<1|1].tag=(t1[num<<1|1].tag+t1[num].tag)%mod;
t1[num].tag=0;
return;
}
void push_down2(int num)
{
if(!t2[num].tag) {
return;
}
t2[num<<1].val=(t2[num<<1].val+t2[num].tag*(p[t2[num<<1].l-1]+1+p[t2[num<<1].r])%mod*(p[t2[num<<1].r]-p[t2[num<<1].l-1])%mod*inv2%mod)%mod;
t2[num<<1].tag=(t2[num<<1].tag+t2[num].tag)%mod;
t2[num<<1|1].val=(t2[num<<1|1].val+t2[num].tag*(p[t2[num<<1|1].l-1]+1+p[t2[num<<1|1].r])%mod*(p[t2[num<<1|1].r]-p[t2[num<<1|1].l-1])%mod*inv2%mod)%mod;
t2[num<<1|1].tag=(t2[num<<1|1].tag+t2[num].tag)%mod;
t2[num].tag=0;
return;
}
void change1(int num,int l,int r,long long val)
{
if((t1[num].l>r)||(t1[num].r<l)) {
return;
}
if((t1[num].l>=l)&&(t1[num].r<=r)) {
t1[num].val=(t1[num].val+val*(p[t1[num].r]-p[t1[num].l-1]))%mod;
t1[num].tag=(t1[num].tag+val)%mod;
return;
}
push_down1(num);
change1(num<<1,l,r,val),change1(num<<1|1,l,r,val);
t1[num].val=(t1[num<<1].val+t1[num<<1|1].val)%mod;
return;
}
void change2(int num,int l,int r,long long val)
{
if((t2[num].l>r)||(t2[num].r<l)) {
return;
}
if((t2[num].l>=l)&&(t2[num].r<=r)) {
t2[num].val=(t2[num].val+val*(p[t2[num].l-1]+1+p[t2[num].r])%mod*(p[t2[num].r]-p[t2[num].l-1])%mod*inv2%mod)%mod;
t2[num].tag=(t2[num].tag+val)%mod;
return;
}
push_down2(num);
change2(num<<1,l,r,val),change2(num<<1|1,l,r,val);
t2[num].val=(t2[num<<1].val+t2[num<<1|1].val)%mod;
return;
}
long long query1(int num,int l,int r)
{
if((t1[num].l>r)||(t1[num].r<l)) {
return 0;
}
if((t1[num].l>=l)&&(t1[num].r<=r)) {
return t1[num].val;
}
push_down1(num);
return (query1(num<<1,l,r)+query1(num<<1|1,l,r))%mod;
}
long long query2(int num,int l,int r)
{
if((t2[num].l>r)||(t2[num].r<l)) {
return 0;
}
if((t2[num].l>=l)&&(t2[num].r<=r)) {
return t2[num].val;
}
push_down2(num);
return (query2(num<<1,l,r)+query2(num<<1|1,l,r))%mod;
}
long long pow(long long num,long long times)
{
long long res=1;
while(times) {
if(times&1) {
res=res*num%mod;
}
num=num*num%mod,times>>=1;
}
return res;
}
int main()
{
freopen("rng.in","r",stdin);
freopen("rng.out","w",stdout);
scanf("%d",&n);
siz=n*3;
for(int i=1;i<=n;++i) {
scanf("%d%d",&a[i].l,&a[i].r);
a[i].ll=a[i].l+1;
}
make_map();
build1(1,1,siz),build2(1,1,siz);
for(int i=n;i;--i) {
ans=(ans+((a[i].r+inv2)*query1(1,0,a[i].mr)%mod-(a[i].l+inv2)*query1(1,0,a[i].ml)%mod+query2(1,0,a[i].ml)-query2(1,0,a[i].mr))%mod*pow(a[i].r-a[i].l,mod-2)%mod)%mod;
change1(1,a[i].mll,a[i].mr,pow(a[i].r-a[i].l,mod-2));
change2(1,a[i].mll,a[i].mr,pow(a[i].r-a[i].l,mod-2));
}
printf("%lld\n",(ans+mod)%mod);
return 0;
}