「ABC272Ex」Flipping Coins 2

题目

点这里看题目。


你有一个长度为 \(N\) 的序列 \(\{A_k\}_{k=1}^N\),序列每个元素都是 \([0,N-1]\) 范围内的整数。

你还有另外一个长度为 \(N\) 的序列 \(\{B_k\}_{k=0}^{N-1}\)。初始时,\(B\) 中所有元素都是 \(0\)

假设有一个 \(1\sim N\) 的排列 \(p\),那么进行 \(N\) 次操作,对于第 \(k\) 次操作(\(1\le k\le N\)),你需要:

  • 对于 \(0\le j\le A_{p_k}\),将 \(B_{(k-1+j)\bmod N}\) 加一。

设这个排列的权值为操作完成后 \(B\) 中偶数元素的个数。求等概率从 \(S_N\) 选一个排列进行操作时,排列权值的期望。

答案对 \(998244353\) 取模。

所有数据满足 \(1\le N\le 2\times 10^5,0\le A_k<N\)

分析

Ex 这么有实力的吗?

很显然我们可以直接统计排列权值之和,然后变成统计 \(B\) 中每个元素是偶数的次数。很显然根据对称性,最终 \(B\) 中每个元素是偶数的次数是一样的,所以我们研究一个 \(B\) 即可。为了避免讨论环,我们选择 \(B_{N-1}\)

那么我们已经可以写出一个 DP 了:记 \(c_v=\sum_{k=1}^N[A_k=v]\),则设 \(f_{i,j}\) 表示最终排列中后 \(i\) 个元素中,还剩 \(j\) 个空位的方案数。转移很 common,不说了。

DP 结束之后,需要做一个二项式反演,然后求一个和,就可以得到答案。


然而上面的方法很恼火,直接优化难以降到 \(O(n^2)\) 以下。主要有两点让人不适:

  1. 转移形式很复杂。由于同样元素,我们不得不在转移里面引入和式,而且在 \(c_v\) 的背景之下难以去除。

  2. 转移中,求和指标始终配的是一个负系数。这导致我们在向 GF 等构造靠拢时,不得不引入 \(x^{-1}\),不自然。

  3. 阻力最大的一点是,我们需要及时去除 \(j<0\) 的项。这一点基本上直接阻断了任何形式的卷积优化。

比较难办的 1、3 两点,指向的都是转移形式复杂,暗示应当抛弃“分组转移”的策略,所以我们尝试把转移均摊到每一次操作上。换言之,把 \(A\) 排序之后,我们可以设 \(L_i=\max_{A_j\ge N-i+1}j\),则第 \(i\) 次操作可以翻转 \(N-1\) 当且仅当 \(p_i\ge L_i\),这就变成了关于 \(p\) 元素本身的限制。(这里的 \(p\) 指向的是题面中的“排列”)

Remark.

仍然是思考了很久的问题:如何避免“前期得到本质相同但形式不好的结果,导致后续的优化无法进行”这样的问题?

至少从这道题中,可以得到一点启发:在进行后续的优化之前,先尝试将当前的形式化得更简洁一些。尤其是后续优化遇到困难的时候,更有必要重新铺一铺前面的路

代数工具不一定是万能的,尤其是工具本身就不齐全的前提下。所以不要把所有的障碍全部堆积起来,试图在数学推导过程中解决!

显然 \(B_i\) 是单调不增的(这和原来那个 DP 依赖的单调性是相似的),我们仍然可以轻易地写出一个 DP:\(f_{i,j}\) 表示最终排列的前 \(i\) 项中,可以贡献到 \(B_{N-1}\) 的项有 \(j\) 个的方案数。

由于转移比较重要,我们还是写一下:

\[f_{i,j}=f_{i-1,j}+(N-L_i+1-(j-1))f_{i-1,j-1}=f_{i-1,j}+(N-L_i-j)f_{i-1,j-1} \]


考虑优化这个运算过程。结合这道题的 Ex 身份以及 \(998244353\) 这个模数,我们尝试向生成函数这个方向靠一靠。

很显然,我们应当将 \(j\) 作为指数。注意到 \(j\) 也作为系数出现,我们可能需要用到导数。但是你在什么时候见到过像 \(x^{j-1}\rightarrow jx^j\) 这种“不仅指数进入系数,次数还要上升”的变换呢?很显然,我们需要提前处理一下——翻转下标

那么,我们令 \(g_{i,j}=f_{i,i-j}\),于是得到新的转移:

\[g_{i,j}=g_{i-1,j-1}+(N-L_i-i+1+j)g_{i-1,j} \]

Remark.

如果这里不翻转会怎么样?我们可能不得不面对 \(\vartheta x=x(\vartheta+1)\) 这样复杂的算子。

有时候这样的转换可能看起来比较朴素,但是自己操作起来就不一定想得到。

有时候可能觉得这样的转换“没有意义”,因为“搞不好之后哪里就会出现对称的障碍,导致‘翻转’失效”。——但是,既然当前不会失效,就先用它解决这个问题呗。

\(G_i(x)=\sum_{j\ge 0}g_{i,j}x^j,C_i=N-L_i-i+1\),我们有:

\[G_i(x)=xG_{i-1}(x)+C_iG_{i-1}(x)+xG'_{i-1}(x) \]

到这里,这些处理都还算比较可以理解的。但是下面这一步,确实就有一点出人意料了——我们需要在左右两侧同时配凑一个因式 \(e^x\),看一看有什么变化:

\[\begin{aligned} G_i(x)e^x &=xG_{i-1}(x)e^x+C_iG_{i-1}(x)e^x-xG'_{i-1}(x)e^x\\ &=x(G_{i-1}(x)e^x+G'_{i-1}(x)e^x)+C_iG_{i-1}(x)e^x\\ &=x(G_{i-1}(x)e^x)'+C_i(G_{i-1}(x)e^x) \end{aligned} \]

Remark.

从数列推导的角度来说,这种方法其实是很常见的嘛。

我们的目的,其实就是求出 \(H_N(x)\) 的通项式,而已知的是递推式。这里的操作,可以和 “求和因子”方法挂钩:配一个因子,目的在简化求和。

这里不同的地方在于,递推式中有导数出现,所以配的因子也和普通数列有所不同。如果从构造过程来看的话,可能还是从 \(G_{i-1}(x)+G_{i-1}'(x)\) 的结构出发比较好——这样我们可以想到用 \(e^x\) 把它收拢。

奇妙的结果。我们发现 \(G_i(x)e^x\) 可以作为整体得到一个新的递推式。设 \(H_i(x)=G_i(x)e^x\),则 \(H_i(x)=xH'_{i-1}(x)+C_iH_{i-1}(x)\)。提取 \([x^j]\)

\[h_{i,j}=jh_{i-1,j}+C_ih_{i-1,j}=(C_i+j)h_{i-1,j} \]

很简洁!这是令人激动的结果!因为我们已知 \(H_0(x)=e^x\),所以我们马上就可以得到:

\[h_{N,j}=\frac{1}{j!}\prod_{i=1}^N(C_i+j) \]

这是什么?后面的乘积式是关于 \(j\) 的多项式函数,所以我们只需要进行一次多点求值即可得到 \(h_N\)!知道了 \(H_N(x)\),后续的 \(G_N\) 以及二项式反演,也就都不成问题了。

所以,我们可以 \(O(N\log^2N)\) 地解决这个问题。

代码

代码就是套板子,而且我不想写多点求值,所以没有写代码。

posted @ 2022-10-10 16:40  crashed  阅读(134)  评论(1编辑  收藏  举报