题解 QOJ7219【The Mighty Spell】
题解 QOJ7219【The Mighty Spell】
QOJ7219 The Mighty Spell。这里是原题的一个加强版!
题目描述
你的好朋友 Bob 今天得到了一个字符串 \(\{a_i\}\),它由 \(n\) 个 \([1,m]\) 的字符(也就是正整数)组成。Alice 将送 Bob 一个布尔序列 \(\{b_i\}\),它由 \(n\) 个布尔变量组成,每个布尔变量要么是 \(0\) 要么是 \(1\)。Alice 会在所有 \(2^n\) 个可能的布尔序列中等概率随机一个送给 Bob。Bob 对这个布尔序列的喜爱度定义为:
- 如果有一种字符 \(c\in [1, m]\),使得不存在 \(1\leq i\leq n\) 满足 \(a_i=c\) 且 \(b_i=1\),那么 Bob 会因为字符 \(c\) 没有出现在序列中而感到很生气,对它的喜爱度为 \(0\)。
- 否则,Bob 会对 \(\{b_i\}\) 中一个长度为 \(\ell\) 的极长的 \(1\) 的连续段产生 \(f(\ell)\) 的喜爱度,对整个 \(\{b_i\}\) 的喜爱度是所有极长的 \(1\) 的连续段的喜爱度的和。
- 上文中,\(f(x)=\sum_{i=0}^{k-1}f_ix^i\) 是一个 \(k-1\) 次多项式,各项系数 \(\{f_i\}\) 输入给定。
Bob 请你帮她求出她对 Alice 送给她的布尔序列的喜爱度的期望。
由于字符串 \(\{a_i\}\) 可能非常长,Bob 决定以游程编码形式呈现它。游程编码字符串包含 \(n_0\) 部分,每部分有 \(p_i\) 个相同字符 \(c_i\)。例如,字符串 \(\{0, 0, 1, 1, 1, 1\}\) 有两部分,其中 \(p_1=2, c_1=0, p_2=4, c_2=1\)。
对于所有数据:\(1\leq n\leq 10^{18}\),\(1\leq n_0\leq 2\times 10^5\),\(1\leq m\leq 30\),\(1\leq k\leq 20\),\(1\leq a_i\leq m\),\(0\leq f_{i}<998,244,353\),\(\sum p_i= n\),\(1\leq c_i\leq m\)。
subtask 1
\(n\leq 20\)。指数级暴力。
subtask 2
\(n\leq 300, m\leq 8\)。把搜索改为 dp,大概可以做到 \(O(nk+n^22^m)\)。
subtask 5
\(m=1\)。即所有的方案都不会因为没有字符出现而没有喜爱度。此时枚举一个造成贡献的极长子区间的长度,\(O(nk)\) 或 \(O(nk+n\log n)\) 地计算。
subtask 6
\(m\leq 8\)。二项式反演,钦定集合 \(S\) 中的字符不出现,其它字符不管是否出现,容斥系数为 \((-1)^{|S|}\)。然后整个序列被划分为若干连续段,根据 subtask 3 的做法计算方案数,这里计算一个 \(S\) 的答案是 \(O(n)\) 的,总时间复杂度 \(O(nk+n2^m)\)。
subtask 4
\(n\leq 2000\)。定义题目中的多项式代入 \(n\) 的结果为 \(=\sum_{k=1}^n(n-k+1)f(k)\),即反演得到一个新的确定的函数 \(f(k)\),这样只需要考虑每个段而不是极长的段。枚举每个段 \([l, r]\),定义确定激活这个段(指这个区间上 \(b_i=1\))以后其他字符激活的方案数 \(w(l, r)\)。为计算之,则定义 \(S(l, r)\) 表示这个区间中的字符集合,\(q(c)\) 表示不在 \([l, r]\) 中的字符 \(c\) 的个数。则有 \(w(l, r)=\prod_{c\in S}2^{q(c)}\cdot \prod_{c\not\in S}(2^{q(c)}-1)\)。可以暴力计算,\(O(nk+mn^2)\) 或 \(O(nk+n^2)\)。
subtask 7
\(a_i\) 单调不降。记字符 \(c\) 的出现次数 \(cnt_c\),在 subtask 5 的基础上,枚举这个区间左右端点是哪两个字符 \(i, j\),然后观察到这样会有 \(O(c_i+c_j)\) 种长度,每一种长度里面因为 \(i, j\) 字符都出现在 \(S\) 中,具体 \(i, j\) 有多少个不关心,只需要关心它们一共有多少个,所以每一种长度对应的 \(w\) 都是一样的,而且可以递推计算。时间复杂度 \(O(\sum_{i=1}^m\sum_{j=i}^m(c_i+c_j))=O(nk+mn)\)。
subtask 9
\(n\leq 200000, m\leq 50\)。在 subtask 5 的基础上,考虑固定 \(l\),右移 \(r\) 的过程中,\(S(l, r)\) 只会更改 \(O(m)\) 次,将这些更改的断点记录为 \(r_1, r_2, \cdots, r_m\) 表示 \(r_k\) 是第一个满足 \(S(l, r_{k-1})\neq S(l, r_k)\) 的 \(r\),当然 \(r_1=l\)。对于 \(r_k\leq r<r_{k+1}\) 的 \(r\),可以发现 \(S(l, r)\) 的前半部分每次右移都除以二。因此我们定义 \(w'(l, r)=w(l, r)\cdot 2^{r-l+1}\),这样 \([r_k, r_{k+1})\) 这一段的 \(w'\) 就是常数。如果最后统计了 \(A_t=\sum_{l=1}^{n-t+1}w'(l, l+t-1)\),则答案就是 \(\sum_{t=1}^nA_tf(t)/2^t\),而枚举 \(l\) 以后若能快速维护 \(w'\) 则能差分求出 \(A\)。
考虑已经知道 \(l\) 的答案,计算 \(l-1\) 的答案。则会插入一个新断点 \(r_1=l\),修改 \(O(m)\) 个断点的答案。都是可以计算的。总复杂度 \(O(nk+n(m+\log mod))\)。
subtask 12
可以归纳证明,若题目输入的多项式为 \(f_0(x)\),则有 \(f(x)=f_0(x)-2f_0(x-1)+f_0(x-2)\)(边界情况 \(f(1)=f_0(1), f(2)=f_0(2)-2f_0(1)\),需要特殊处理,这部分并不难)。这说明 \(f(x)\) 的 \(k\) 项系数可以被写出来,只需要做两次多项式平移,而这可以以 \(O(k^2)\) 地完成。
仔细整理发现我们实际上只需要快速求出以下两个和式:
其中 \(n, m, t\) 是参数,一共需要求值大约 \(O(nm)\) 次。这个问题太困难了,考虑引入科技:
参考资料:有限微积分与数列求和 - 洛谷专栏 “不定和式与分部求和”一节
有了这个式子,我们将 \(f(x)\) 转为下降幂,并求出对应的 \(g(x)\),使 \(\sum_{i=l}^{r-1}f(i)/2^i=g(r)-g(l)\)。
上文的第一个式子可以转化为 \(\sum_{i=1}^n(n-i+1)f(i)/2^i\),需要对 \(f(x)\) 和 \(xf(x)\) 进行变换。
第二个式子先对 \(f(x)\) 变换使其变为
注意到 \(g(x)\) 也是一个下降幂多项式乘上 \((1/2)^x\) 的形式,可以对 \(g(x)2^x\) 再次变换,这样就能求了。
复杂度 \(O(nm(k+\log n))\) 其中 \(\log n\) 是快速幂的代价,但实际上可以写光速幂去掉这个 \(\log n\)。
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18547489/solution-QOJ7219