【LOJ】#2527. 「HAOI2018」染色
阿新 • • 發佈:2018-12-01
題解
簡單容斥題
至少選了\(k\)個顏色恰好出現\(S\)次方案數是
\(F[k] = \binom{M}{k} \frac{N!}{(S!)^{k}(N - i * S)!}(M - k)^{N - i * S}\)
然後恰好\(k\)個顏色恰好出現\(k\)次就是
\(g[k] = \sum_{j = k}^{M} (-1)^{k - j} \binom{j}{k}F[j]\)
然後就是
\(g[k]*k! = \sum_{j = k}^{M}\frac{(-1)^{j - k}}{(j - k)!} F[j]*j!\)
後面的只要把其中一個指數取反,就可以NTT卷積優化了
程式碼
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define pdi pair<db,int> #define mp make_pair #define pb push_back #define enter putchar('\n') #define space putchar(' ') #define eps 1e-8 #define MAXN 100005 #define mo 974711 //#define ivorysi using namespace std; typedef long long int64; typedef double db; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } const int MOD = 1004535809; const int MAXL = 1 << 20; int W[MAXL + 5],a[MAXN],N,M,S,F[MAXN]; int fac[10000005],invfac[10000005]; int f[1000005],g[1000005]; int inc(int a,int b) { return a + b >= MOD ? a + b - MOD : a + b; } int mul(int a,int b) { return 1LL * a * b % MOD; } int C(int n,int m) { if(n < m) return 0; return mul(fac[n],mul(invfac[m],invfac[n - m])); } int fpow(int x,int c) { int res = 1,t = x; while(c) { if(c & 1) res = mul(res,t); t = mul(t,t); c >>= 1; } return res; } void NTT(int *p,int L,int on) { for(int i = 1 , j = L >> 1 ; i < L - 1 ; ++i) { if(i < j) swap(p[i],p[j]); int k = L >> 1; while(j >= k) { j -= k; k >>= 1; } j += k; } for(int h = 2 ; h <= L ; h <<= 1) { int wn = W[(MAXL + on * MAXL / h) % MAXL]; for(int k = 0 ; k < L ; k += h) { int w = 1; for(int j = k ; j < k + h / 2 ; ++j) { int u = p[j],t = mul(w,p[j + h / 2]); p[j] = inc(u,t); p[j + h / 2] = inc(u,MOD - t); w = mul(w,wn); } } } if(on == -1) { int InvL = fpow(L,MOD - 2); for(int i = 0 ; i < L ; ++i) p[i] = mul(InvL,p[i]); } } void Solve() { read(N);read(M);read(S); for(int i = 0 ; i <= M ; ++i) read(a[i]); fac[0] = 1; for(int i = 1 ; i <= 10000000 ; ++i) fac[i] = mul(fac[i - 1],i); invfac[10000000] = fpow(fac[10000000],MOD - 2); for(int i = 10000000 - 1 ; i >= 0 ; --i) invfac[i] = mul(invfac[i + 1],i + 1); W[0] = 1; W[1] = fpow(3,(MOD - 1) / MAXL); for(int i = 2 ; i < MAXL ; ++i) W[i] = mul(W[i - 1],W[1]); int t = 1; for(int i = 0 ; i <= M ; ++i) { if(N / S < i) break; F[i] = mul(C(M,i) , mul(fac[N] , mul(t , invfac[N - i * S]))); F[i] = mul(F[i],fpow(M - i,N - i * S)); t = mul(t,invfac[S]); } for(int i = 0 ; i <= M ; ++i) f[i] = mul(F[i],fac[i]); t = 1; for(int i = 0 ; i <= M ; ++i) { g[M - i] = mul(t,invfac[i]); t = mul(t,MOD - 1); } t = 1; while(t <= 2 * M) t <<= 1; NTT(f,t,1);NTT(g,t,1); for(int i = 0 ; i < t ; ++i) g[i] = mul(g[i],f[i]); NTT(g,t,-1); int ans = 0; for(int i = 0 ; i <= M ; ++i) { g[i + M] = mul(g[i + M],invfac[i]); ans = inc(ans,mul(g[i + M],a[i])); } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }