UOJ450 复读机
题意:n个位置,k种颜色。求有多少种方案使得每种颜色恰出现d的倍数次。
解:d=1就快速幂,n,k很小就DP,记得乘组合数来分配位置。
d = 2 / 3的时候,考虑生成函数。
f(x) = ∑[d | i] / (i!)
然后发现d = 2的时候就是(ex + e-x) / 2,这个东西的k次方可以用二项式定理展开,然后O(klogn)算,log是快速幂。
d = 3的时候用单位根反演,O(k2)枚举系数,同样算。因为我不想学单位根反演就没写...
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 5 const int N = 500010, MO = 19491001; 6 7 int n, k, d; 8 9 inline int qpow(int a, int b) { 10 int ans(1); 11 while(b) { 12 if(b & 1) { 13 ans = (LL)ans * a % MO; 14 } 15 a = (LL)a * a % MO; 16 b = b >> 1; 17 } 18 return ans; 19 } 20 21 namespace DP { 22 int f[110][1010], C[1010][1010]; 23 inline void solve() { 24 f[0][0] = 1; 25 for(int i = 0; i <= 1000; i++) { 26 C[i][0] = C[i][i] = 1; 27 for(int j = 1; j < i; j++) { 28 C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MO; 29 } 30 } 31 for(int i = 0; i < k; i++) { 32 for(int j = 0; j <= n; j++) { 33 for(int p = 0; j + p <= n; p += d) { 34 (f[i + 1][j + p] += (LL)f[i][j] * C[n - j][p] % MO) %= MO; 35 } 36 } 37 } 38 printf("%d\n", f[k][n]); 39 return; 40 } 41 } 42 43 namespace D2 { 44 45 int fac[N], inv[N], invn[N]; 46 47 inline int C(int n, int m) { 48 if(n < 0 || m < 0 || n < m) return 0; 49 return (LL)fac[n] * invn[m] % MO * invn[n - m] % MO; 50 } 51 52 inline void solve() { 53 fac[0] = inv[0] = invn[0] = 1; 54 fac[1] = inv[1] = invn[1] = 1; 55 for(int i = 2; i <= k; i++) { 56 fac[i] = (LL)fac[i - 1] * i % MO; 57 inv[i] = (LL)inv[MO % i] * (MO - MO / i) % MO; 58 invn[i] = (LL)invn[i - 1] * inv[i] % MO; 59 } 60 61 int ans = 0; 62 for(int i = 0; i <= k; i++) { 63 ans += (LL)C(k, i) * qpow(2 * i - k, n) % MO; 64 ans %= MO; 65 } 66 int temp = qpow((MO + 1) / 2, k); 67 68 printf("%lld\n", ((LL)temp * ans % MO + MO) % MO); 69 return; 70 } 71 } 72 73 int main() { 74 75 scanf("%d%d%d", &n, &k, &d); 76 if(d == 1) { 77 printf("%d\n", qpow(k, n)); 78 return 0; 79 } 80 if(n <= 1000 && k <= 100) { 81 DP::solve(); 82 return 0; 83 } 84 if(d == 2) { 85 D2::solve(); 86 return 0; 87 } 88 return 0; 89 }