P5401 [CTS2019]珍珠
大力推式子。
容易想到需要满足的条件是:
\[\sum_i cnt_i \bmod 2 <= n - 2m
\]
好啦我自己想到的部分就到此为止啦
不知道怎么想到的二项式反演:计算钦定有 \(i\) 种颜色出现了奇数次的方案数 \(g_i\),一会儿再说怎么转化成“恰好”的方案数。
接下来需要用到生成函数。有一些需要知道的常识(下面均为EGF,下标从0开始):
\[<1,1,1,1,1,...>=e^x
\]
\[<1,-1,1,-1,1>=e^{-x}
\]
\[\large<0,1,0,1,0,1,...>=\frac{e^x-e^{-x}}{2}
\]
\[\large e^{ax}=<1,a,a^2,a^3,...>
\]
然后有:
\[\large g_i= {D\choose i} n![x^n](\frac{e^x-e^{-x}}{2})^i(e^x)^{d-i}
\]
二项式定理,拆组合数,化为卷积形式:
\[=(1/2^i) * {D \choose i} n! [x^n]\sum_{j}{i\choose j}(e^x)^j(-e^{-x})^{i-j}(e^x)^{D-i}
\]
\[=\frac{D!n!(-1)^i}{(D-i)!2^i}\sum_{j}\frac{(-1)^j}{j!} * \frac{1}{(i-j)!} [x^n]e^{x(2j-2i+D)}
\]
\[=\frac{D!n!(-1)^i}{(D-i)!2^i}\sum_{j}\frac{(-1)^j}{j!} * \frac{1}{(i-j)!} * \frac{(D-2(i-j))^n}{n!}
\]
\[=\frac{D!(-1)^i}{(D-i)!2^i}\sum_{j}\frac{(-1)^j}{j!} * \frac{(D-2(i-j))^n}{(i-j)!}
\]
\[\large A_k=\frac{(-1)^k}{k!}, B_k=\frac{(D-2k)^n}{k!},H_k=A_k*B_k
\]
\[\large g_i=\frac{D!(-1)^i}{(D-i)!2^i}h_i
\]
这样我们就能够 \(O(nlogn)\) 求出 \(g_i\) 了。
然后考虑二项式反演:
\[f_k=\sum_{i}^D (-1)^{i-k} {i\choose k}g_i
\]
\[=(1/k!) * \sum_{i=0}^D i!g_i * \frac{(-1)^{i-k}}{(i-k)!}
\]
仍然设 \(A_i=i!g_i,B_i=\frac{(-1)^i}{i!}\)
那么:
\[f_k=(1/k!) * \sum_{i} A_iB_{i-k}
\]
这需要一种特殊的卷积。翻转 \(B\) 数组,即 \(B^r_{i}=B_{D-i}\),则:
\[f_k=(1/k!)\sum_iA_iB^r_{D-i+k}
\]
这样的话下标之和就是定值 \(D+k\) 了。
\[f_k=(1/k!)C_{D+k}
\]
关键代码:
for (register int i = 0; i <= d; ++i) {
if (i & 1) A[i] = P - jieni[i];
else A[i] = jieni[i];
B[i] = quickpow(((d - 2 * i) % P + P) % P, n) * jieni[i] % P;
}
ntt(A, 1), ntt(B, 1);
for (register int i = 0; i < limi; ++i)
h[i] = A[i] * B[i] % P, A[i] = B[i] = 0;
ntt(h, -1);
for (register int i = 0; i <= d; ++i) {
g[i] = (i & 1 ? -1 : 1) * jie[d] * jieni[d - i] % P * quickpow(quickpow(2, i), P - 2) % P * h[i] % P;
if (g[i] < 0) g[i] += P;
}
for (register int i = 0; i <= d; ++i) {
A[i] = jie[i] * g[i] % P;
B[d - i] = (i & 1 ? -1 : 1) * jieni[i] % P;
if (B[d - i] < 0) B[d - i] += P;
}
ntt(A, 1), ntt(B, 1);
for (register int i = 0; i < limi; ++i) f[i] = A[i] * B[i] % P, A[i] = B[i] = 0;
ntt(f, -1);
ll ans = 0;
for (register int k = 0; k <= n - m - m; ++k) {
ans = (ans + jieni[k] * f[d + k]) % P;
}