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;
}
posted @ 2020-08-04 11:22  JiaZP  阅读(103)  评论(0编辑  收藏  举报