2022 牛客多校 第二场 E - Falfa with Substring
题意
记 \(F_{n,k}\) 表示串长 \(n\) 且 "bit" 串恰好出现 \(k\) 次的本质不同字串个数
现在给定 \(n\) , 求 \(F_{n,0},F_{n,1},\cdots,F_{n,k},\), 要求答案对 \(998244353\) 取模, \(n \leq 10^6\).
思路
FFT
记 \(f_k = F_{n,k}\) , 则有
\[f_k = 26^{n-3k}\cdot C_{n-2k}^k - \sum_{i=k+1}^nC_i^k\cdot f_i
\]
其中, 减号左边是很好推出, 右边表示减去重复记录的方案数, 即 \(i\) 个中以左边形式被数出, 但是只有其中 \(k\) 个 "bit" 串被保留 ( 本质上是因为选 "bit" 串时, 其他地方在 \(26^{n-3k}\) 时又出现了 "bit" 所以要去重 )
看起来像是分治 FFT, 但是 \(n\leq 10^6\)
记 \(g_k = 26^{n-3k}\cdot C_{n-2k}^k\) , 考虑暴力展开右边, 逐项将 \(f_{k+1},f_{k+2},\cdots\) 代入消去, 化简得到
\[f_k = \sum_{i=k}^n (-1)^{i-k}\cdot C_{k+i}^k \cdot g_{k+i}
\]
展开组合数, 移项
\[k!f_k = \sum_{i=k}^n \frac{(-1)^{i-k}}{(i-k)!} \cdot (i!\cdot g_i)
\]
\(k!f_k\) 的记作 \(A_k\)
\(\frac{(-1)^{i-k}}{(i-k)!}\)记作 \(H_{i-k}\)
\(i!\cdot g_i\) 记作 \(G_i\)
注意到 \(k = i - (i - k)\)
跑个差卷积即可 ( 把某一个多项式 reverse 过来就行 )
代码
void sol() {
int n;
std::cin >> n;
std::vector<int> fac(n + 1, 1),ifac(n + 1, 1);
for(int i=2;i<=n;++i) {
fac[i] = mul(fac[i - 1], i);
}
ifac[n] = inv(fac[n]);
for(int i=n-1;i>=2;--i) {
ifac[i] = mul(i + 1, ifac[i + 1]);
}
auto C = [&](int n, int m) {
if(n < m || m < 0) return 0;
return mul(fac[n], mul(ifac[n - m], ifac[m]));
};
poly H(n + 1), G(n + 1);
H[0] = 1;
for(int i = 1; i <= n; ++i) {
H[i] = MOD - H[i - 1];
}
for(int i = 0; i <= n; ++i) {
H[i] = mul(H[i], ifac[i]);
}
for(int i = 0; i <= n; ++i) {
if(n - 3 * i >= 0) G[i] = mul(C(n - 2 * i, i), mul(qpow(26, n - 3 * i), fac[i]));
else G[i] = 0;
}
std::reverse(H.begin(), H.end());
poly F = Poly::mul(H, G);
F.resize(2 * n + 1);
for(int i=n;i<2*n+1;++i) {
F[i] = mul(F[i], ifac[i - n]);
}
for(int i=n;i<2*n+1;++i) {
std::cout << F[i] << ' ';
}
}
Living with bustle, hearing of isolation.