6508. 【GDOI2020模拟03.11】我的朋友们

题目

有一个长度为\(n\)的数列\(a_i\),一开始将数列的前\(L\)个丢入队列中。
一次操作是对于队列中的每个数\(a_i\),有\(a_i\)的几率有\(1\)的贡献。设贡献和为\(x\)
然后将队列中前\(x\)个弹出去,再从数列中接着\(x\)个。
如果数列中的数取完了,操作停止。
问期望进行多少次操作。


思考历程

一开始就看错了题意,于是这就变成的了一道神仙题。
只想到了\(a_i\)相等的情况。
由于时间不够,写出来之后调都不调就交了。
结果自然是爆0。
(话说我在写这个东西的时候没有用分治NTT……不知道是我的方法错了,还是确实能不用分治NTT……)


正解

\(f_i\)为当前队列中的数在\([i,i+L)\)中的期望。
转移十分显然,这里就不写了。
直接暴力转移肯定不能过,接下来就是在这个东西的基础上优化。

把整个序列倒过来做,\(f_i\)就变成了当前队列中的数在\((i-L,i)\)中的期望。
\(P_i=\prod_{j=i-L+1}^i (1-a_j+a_jx)\)
随便推一推得:

\[f_i=\frac{1+\sum_{j=1}^Lf_{i-j}[x^j]P_i}{1-[x^0]P[i]} \]

接下来问题是处理\(\sum_{j=1}^Lf_{i-j}[x^j]P_i\),其它的都很好办。
\(F_i=\sum_{j=L}^if_jx^j\)
于是\(\sum_{j=1}^Lf_{i-j}[x^j]P_i=[x^i](F_{i-1}P_i)\)
这下就好看很多了。

考虑分治NTT。假如现在要计算区间\([l,r]\)的答案。
对于每个\(i\in[l,r]\),我们把\(P_i\)的公因数提取出来,就是\(\prod_{j=r-L+1}^l(1-a_j+a_jx)\)
\(F_{l,r}^{'}=F_{l-1}\prod_{j=r-L+1}^l(1-a_j+a_jx)\),这就是前面\([1,l-1]\)区间对每一个\(i\in [l,r]\)共有的贡献,可以一起算。
\([x^i]F_{i,i}^{'}\)就是对\(f_i\)的贡献。
考虑如何从\(F_{l,r}^{'}\)转移至\(F_{l,mid}^{'}\)\(F_{mid+1,r}^{'}\)

\[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) \]

\[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) \]

上面式子中的那堆连乘都是可以用分治NTT预处理的。
看起来这个东西并没有优秀到哪里去啊……

我们想要求的,仅仅是\([x^i]F_{i,i}^{'}\)
对于\(F_{l,r}^{'}\),如果它一直转移到了叶子节点,那么乘上的多项式的次数是\(O(r-l)\)级别的。
我们最终只要对\(i\in [l,r]\)的所有\(i\)有用的项,这意味着有些次数很小的项,他们次数增高\(O(r-l)\)之后依然不会对任何\(i\in[l,r]\)\(i\)产生影响,这个项就是没用的。
对于没用的项,那就可以忽略不计。
所以,只需要存最后\(O(r-l)\)项就可以了。题解说标程存了最后\(2(r-l+1)\)项。

于是这题就做完了,时间复杂度\(O(n \lg^2 n)\)


总结

一个晚上,两个小时思考,再加一个小时写博客整理思路。
这种到现在pty都没有AC的题目,我不知道写出来要多长时间。
就先把题解晾在这里好了……

这题的精髓,除了乱推一波式子以外,我认为是最后的那个保留最后几项的那个操作。
我终于明白了原来分治NTT还能这么搞。

posted @ 2020-03-13 21:07  jz_597  阅读(255)  评论(0编辑  收藏  举报