题目
有一个长度为
n
n
n的数列
a
i
a_i
ai,一开始将数列的前
L
L
L个丢入队列中。
一次操作是对于队列中的每个数
a
i
a_i
ai,有
a
i
a_i
ai的几率有
1
1
1的贡献。设贡献和为
x
x
x。
然后将队列中前
x
x
x个弹出去,再从数列中接着
x
x
x个。
如果数列中的数取完了,操作停止。
问期望进行多少次操作。
思考历程
一开始就看错了题意,于是这就变成的了一道神仙题。
只想到了
a
i
a_i
ai相等的情况。
由于时间不够,写出来之后调都不调就交了。
结果自然是爆0。
(话说我在写这个东西的时候没有用分治NTT……不知道是我的方法错了,还是确实能不用分治NTT……)
正解
设
f
i
f_i
fi为当前队列中的数在
[
i
,
i
+
L
)
[i,i+L)
[i,i+L)中的期望。
转移十分显然,这里就不写了。
直接暴力转移肯定不能过,接下来就是在这个东西的基础上优化。
把整个序列倒过来做,
f
i
f_i
fi就变成了当前队列中的数在
(
i
−
L
,
i
)
(i-L,i)
(i−L,i)中的期望。
设
P
i
=
∏
j
=
i
−
L
+
1
i
(
1
−
a
j
+
a
j
x
)
P_i=\prod_{j=i-L+1}^i (1-a_j+a_jx)
Pi=∏j=i−L+1i(1−aj+ajx)
随便推一推得:
f
i
=
1
+
∑
j
=
1
L
f
i
−
j
[
x
j
]
P
i
1
−
[
x
0
]
P
[
i
]
f_i=\frac{1+\sum_{j=1}^Lf_{i-j}[x^j]P_i}{1-[x^0]P[i]}
fi=1−[x0]P[i]1+∑j=1Lfi−j[xj]Pi
接下来问题是处理
∑
j
=
1
L
f
i
−
j
[
x
j
]
P
i
\sum_{j=1}^Lf_{i-j}[x^j]P_i
∑j=1Lfi−j[xj]Pi,其它的都很好办。
设
F
i
=
∑
j
=
L
i
f
j
x
j
F_i=\sum_{j=L}^if_jx^j
Fi=∑j=Lifjxj
于是
∑
j
=
1
L
f
i
−
j
[
x
j
]
P
i
=
[
x
i
]
(
F
i
−
1
P
i
)
\sum_{j=1}^Lf_{i-j}[x^j]P_i=[x^i](F_{i-1}P_i)
∑j=1Lfi−j[xj]Pi=[xi](Fi−1Pi)
这下就好看很多了。
考虑分治NTT。假如现在要计算区间
[
l
,
r
]
[l,r]
[l,r]的答案。
对于每个
i
∈
[
l
,
r
]
i\in[l,r]
i∈[l,r],我们把
P
i
P_i
Pi的公因数提取出来,就是
∏
j
=
r
−
L
+
1
l
(
1
−
a
j
+
a
j
x
)
\prod_{j=r-L+1}^l(1-a_j+a_jx)
∏j=r−L+1l(1−aj+ajx)
设
F
l
,
r
′
=
F
l
−
1
∏
j
=
r
−
L
+
1
l
(
1
−
a
j
+
a
j
x
)
F_{l,r}^{'}=F_{l-1}\prod_{j=r-L+1}^l(1-a_j+a_jx)
Fl,r′=Fl−1∏j=r−L+1l(1−aj+ajx),这就是前面
[
1
,
l
−
1
]
[1,l-1]
[1,l−1]区间对每一个
i
∈
[
l
,
r
]
i\in [l,r]
i∈[l,r]共有的贡献,可以一起算。
[
x
i
]
F
i
,
i
′
[x^i]F_{i,i}^{'}
[xi]Fi,i′就是对
f
i
f_i
fi的贡献。
考虑如何从
F
l
,
r
′
F_{l,r}^{'}
Fl,r′转移至
F
l
,
m
i
d
′
F_{l,mid}^{'}
Fl,mid′和
F
m
i
d
+
1
,
r
′
F_{mid+1,r}^{'}
Fmid+1,r′
F
l
,
m
i
d
′
=
F
l
−
1
∏
j
=
m
i
d
−
L
+
1
l
(
1
−
a
j
+
a
j
x
)
=
F
l
,
r
′
∏
j
=
m
i
d
−
L
+
1
r
−
L
(
1
−
a
j
+
a
j
x
)
F_{l,mid}^{'}=F_{l-1}\prod_{j=mid-L+1}^l(1-a_j+a_jx)\\=F_{l,r}^{'}\prod_{j=mid-L+1}^{r-L}(1-a_j+a_jx)
Fl,mid′=Fl−1j=mid−L+1∏l(1−aj+ajx)=Fl,r′j=mid−L+1∏r−L(1−aj+ajx)
F
m
i
d
+
1
,
r
′
=
F
m
i
d
∏
j
=
r
−
L
+
1
m
i
d
+
1
(
1
−
a
j
+
a
j
x
)
=
F
l
,
r
′
∏
j
=
l
+
1
m
i
d
+
1
(
1
−
a
j
+
a
j
x
)
+
(
∑
i
=
l
m
i
d
f
i
x
i
)
∏
j
=
r
−
L
+
1
m
i
d
+
1
(
1
−
a
j
+
a
j
x
)
F_{mid+1,r}^{'}=F_{mid}\prod_{j=r-L+1}^{mid+1}(1-a_j+a_jx)\\=F_{l,r}^{'}\prod_{j=l+1}^{mid+1}(1-a_j+a_jx)+(\sum_{i=l}^{mid}f_ix^i)\prod_{j=r-L+1}^{mid+1}(1-a_j+a_jx)
Fmid+1,r′=Fmidj=r−L+1∏mid+1(1−aj+ajx)=Fl,r′j=l+1∏mid+1(1−aj+ajx)+(i=l∑midfixi)j=r−L+1∏mid+1(1−aj+ajx)
上面式子中的那堆连乘都是可以用分治NTT预处理的。
看起来这个东西并没有优秀到哪里去啊……
我们想要求的,仅仅是
[
x
i
]
F
i
,
i
′
[x^i]F_{i,i}^{'}
[xi]Fi,i′
对于
F
l
,
r
′
F_{l,r}^{'}
Fl,r′,如果它一直转移到了叶子节点,那么乘上的多项式的次数是
O
(
r
−
l
)
O(r-l)
O(r−l)级别的。
我们最终只要对
i
∈
[
l
,
r
]
i\in [l,r]
i∈[l,r]的所有
i
i
i有用的项,这意味着有些次数很小的项,他们次数增高
O
(
r
−
l
)
O(r-l)
O(r−l)之后依然不会对任何
i
∈
[
l
,
r
]
i\in[l,r]
i∈[l,r]的
i
i
i产生影响,这个项就是没用的。
对于没用的项,那就可以忽略不计。
所以,只需要存最后
O
(
r
−
l
)
O(r-l)
O(r−l)项就可以了。题解说标程存了最后
2
(
r
−
l
+
1
)
2(r-l+1)
2(r−l+1)项。
于是这题就做完了,时间复杂度 O ( n lg 2 n ) O(n \lg^2 n) O(nlg2n)。
总结
一个晚上,两个小时思考,再加一个小时写博客整理思路。
这种到现在pty都没有AC的题目,我不知道写出来要多长时间。
就先把题解晾在这里好了……
这题的精髓,除了乱推一波式子以外,我认为是最后的那个保留最后几项的那个操作。
我终于明白了原来分治NTT还能这么搞。