[CTS2019]珍珠
題目傳送門:
luogu
分析
考慮每種顏色有幾個。假設已經求出了每種顏色的個數爲
方案數就是
考慮這個方案合法的要求。
這是個蠻顯然的轉化,因爲相同顏色兩兩匹配,那麼不能匹配的就是奇數個的哪一個。
考慮求出爲的方案數,答案就是
容易想到EGF。
我們考慮隨便放個隨機變量的方案數的EGF表示方法:
什麼意思呢?
,也就是說當前顏色可以放個,並且消除內部順序的影響,那麼放置個實際上就是卷積次後的次冪係數。
如今我們知道有個要放置的位置是奇數個的。
如何表示只放置奇數個?
偶數個同理爲
然後再用選出這若干個位置。
因此可以得到
這個東西表示取第項係數
這個東西實際上可以直接推,但是比較麻煩。我們退而求其次,先求至少爲個奇數的答案:
然後可以得到
二項式反演一下可以得到
這個東西可以拆組合數用解決。
然後問題轉化爲求
暴力二項式展開:
然後得到
注意到
所以
前面的那坨只和有關係不用管,後面是多項式和卷積結果的第項。
即可
難點在於:1.問題的轉化。2.指數型生成函數的轉化。3.二項式反演的簡化。
其實我覺得第3個是最難的,因爲很容易直接走上直接肝式子的不歸路(雖然有人肝出來了)。前面兩個比較套路吧,主要還是得有模型積累。
代碼
#include<bits/stdc++.h>
const int N = 262144, P = 998244353;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int A[N], B[N], R[N], f[N], fac[N], ivf[N], w[N], L, D, n, m, InvL;
int Pow(int x, int k) {
int r = 1;
for(;k; k >>= 1, x = 1LL * x * x % P)
if(k & 1)
r = 1LL * r * x % P;
return r;
}
int C(int m, int n) {return 1LL * fac[m] * ivf[n] % P * ivf[m - n] % P;}
void Pre(int m) {
int x = 0; L = 1;
for(;(L <<= 1) <= m; ++x) ;
for(int i = 1;i < L; ++i)
R[i] = R[i >> 1] >> 1 | (i & 1) << x;
int wn = Pow(3, (P - 1) / L); w[0] = 1;
for(int i = 1;i < L; ++i)
w[i] = 1LL * w[i - 1] * wn % P;
InvL = Pow(L, P - 2);
}
void NTT(int *F) {
for(int i = 0;i < L; ++i)
if(R[i] > i)
std::swap(F[i], F[R[i]]);
for(int i = 1, d = L >> 1; i < L; i <<= 1, d >>= 1)
for(int j = 0;j < L; j += i << 1) {
int *l = F + j, *r = F + i + j, *p = w, tp;
for(int k = i; k--; ++l, ++r, p += d)
tp = 1LL * *p * *r % P, *r = (*l - tp) % P, *l = (*l + tp) % P;
}
}
int main() {
D = ri(); n = ri(); m = ri();
if(n < (m << 1)) return puts("0"), 0;
if(D <= n - (m << 1)) return printf("%d\n", Pow(D, n)), 0;
fac[0] = 1;
for(int i = 1;i <= D; ++i)
fac[i] = 1LL * fac[i - 1] * i % P;
ivf[D] = Pow(fac[D], P - 2);
for(int i = D; i; --i)
ivf[i - 1] = 1LL * ivf[i] * i % P;
for(int i = 0, w = 1;i <= D; ++i, w = -w)
A[i] = 1LL * w * Pow(D - (i << 1), n) * ivf[i] % P, B[i] = ivf[i];
Pre(D << 1);
NTT(A); NTT(B);
for(int i = 0;i < L; ++i)
A[i] = 1LL * A[i] * B[i] % P;
NTT(A);
for(int i = 0;i <= D; ++i)
f[i] = 1LL * A[L - i & L - 1] * InvL % P * C(D, i) % P * fac[i] % P * Pow(2, P - 1 - i) % P;
for(int i = 0, w = 1;i <= D; ++i, w = -w)
A[i] = 1LL * f[D - i] * fac[D - i] % P, B[i] = w * ivf[i];
for(int i = D + 1; i < L; ++i)
A[i] = B[i] = 0;
NTT(A); NTT(B);
for(int i = 0;i < L; ++i)
A[i] = 1LL * A[i] * B[i] % P;
NTT(A); long long ans = 0;
for(int i = 0;i <= n - (m << 1); ++i) {
int g = 1LL * A[L - (D - i) & L - 1] * InvL % P * ivf[i] % P;
ans += g;
}
printf("%d\n", (ans % P + P) % P);
return 0;
}