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 }
60分代码

 

posted @ 2019-06-30 22:03 huyufeifei 阅读(...) 评论(...) 编辑 收藏