UOJ#449 喂鸽子

题意:有n个鸽子,你每秒随机喂一只鸽子,每只鸽子吃k次就饱了。求期望多少秒之后全饱了。n <= 50, k <= 1000。

解:有两种做法。一种直接DP的n2k做法在。我用的是Min-Max容斥 + NTT优化DP。

先Min-Max容斥,由于鸽子是等价的,所以相当于求m只鸽子期望多少秒之后有一只饱了。

讲不清楚...看题解吧。

注意题解中m个盒子的答案为什么放了i + 1个球,这是因为我们把最后一个球拿出来考虑了。所以唯一放满k个球的盒子的贡献是1 / (k - 1)!

  1 #include <bits/stdc++.h>
  2 
  3 const int MO = 998244353;
  4 const int N = 50010;
  5 
  6 int n, K, fac[N], inv[N], invn[N];
  7 int f[55][N], g[55][N], A[N * 4], B[N * 4], r[N * 4];
  8 
  9 inline int C(int n, int m) {
 10     if(n < 0 || m < 0 || n < m) return 0;
 11     return 1ll * fac[n] * invn[m] % MO * invn[n - m] % MO;
 12 }
 13 
 14 inline int qpow(int a, int b) {
 15     int ans = 1;
 16     while(b) {
 17         if(b & 1) ans = 1ll * ans * a % MO;
 18         a = 1ll * a * a % MO;
 19         b = b >> 1;
 20     }
 21     return ans;
 22 }
 23 
 24 inline int Inv(int x) {
 25     return qpow(x, MO - 2);
 26 }
 27 
 28 inline void prework(int n) {
 29     static int R = 0;
 30     if(R == n) return;
 31     R = n;
 32     int lm = 1;
 33     while((1 << lm) < n) lm++;
 34     for(int i = 0; i < n; i++) {
 35         r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1));
 36     }
 37     return;
 38 }
 39 
 40 inline void NTT(int *a, int n, int f) {
 41     prework(n);
 42     for(int i = 0; i < n; i++) {
 43         if(i < r[i]) {
 44             std::swap(a[i], a[r[i]]);
 45         }
 46     }
 47     for(int len = 1; len < n; len <<= 1) {
 48         int Wn = qpow(3, (MO - 1) / (len << 1));
 49         if(f == -1) Wn = Inv(Wn);
 50         for(int i = 0; i < n; i += (len << 1)) {
 51             int w = 1;
 52             for(int j = 0; j < len; j++) {
 53                 int t = 1ll * a[i + len + j] * w % MO;
 54                 a[i + len + j] = (a[i + j] - t) % MO;
 55                 a[i + j] = (a[i + j] + t) % MO;
 56                 w = 1ll * w * Wn % MO;
 57             }
 58         }
 59     }
 60     if(f == -1) {
 61         int inv = Inv(n);
 62         for(int i = 0; i < n; i++) {
 63             a[i] = 1ll * a[i] * inv % MO;
 64         }
 65     }
 66     return;
 67 }
 68 
 69 int main() {
 70     
 71     scanf("%d%d", &n, &K);
 72     
 73     fac[0] = inv[0] = invn[0] = 1;
 74     fac[1] = inv[1] = invn[1] = 1;
 75     for(int i = 2; i <= n * K; i++) {
 76         fac[i] = 1ll * fac[i - 1] * i % MO;
 77         inv[i] = 1ll * inv[MO % i] * (MO - MO / i) % MO;
 78         invn[i] = 1ll * invn[i - 1] * inv[i] % MO;
 79     }
 80     
 81     int len = 1;
 82     while(len <= n * K) len <<= 1;
 83     g[0][0] = 1;
 84     memcpy(B, invn, K * sizeof(int));
 85     NTT(B, len, 1);
 86     for(int i = 1; i <= n; i++) {
 87         /*for(int j = 0; j <= i * K; j++) {
 88             /// g[i][j] f[i][j] 
 89             for(int k = 0; k < K && k <= j; k++) {
 90                 g[i][j] = (g[i][j] + 1ll * g[i - 1][j - k] * invn[k] % MO) % MO;
 91                 f[i][j] = (f[i][j] + 1ll * f[i - 1][j - k] * invn[k] % MO) % MO;
 92             }
 93             if(j >= K) f[i][j] = (f[i][j] + 1ll * g[i - 1][j - K] * invn[K - 1] % MO) % MO;
 94         }*/
 95         memcpy(A, g[i - 1], n * K * sizeof(int));
 96         memset(A + n * K, 0, (len - n * K) * sizeof(int));
 97         NTT(A, len, 1);
 98         for(int j = 0; j < len; j++) {
 99             A[j] = 1ll * A[j] * B[j] % MO;
100         }
101         NTT(A, len, -1);
102         for(int j = 0; j <= i * K; j++) {
103             g[i][j] = A[j];
104         }
105         memcpy(A, f[i - 1], n * K * sizeof(int));
106         memset(A + n * K, 0, (len - n * K) * sizeof(int));
107         NTT(A, len, 1);
108         for(int j = 0; j < len; j++) {
109             A[j] = 1ll * A[j] * B[j] % MO;
110         }
111         NTT(A, len, -1);
112         for(int j = 0; j <= i * K; j++) {
113             f[i][j] = A[j];
114             if(j >= K) {
115                 f[i][j] = (f[i][j] + 1ll * g[i - 1][j - K] * invn[K - 1] % MO) % MO;
116             }
117         }
118     }
119     
120     int ans = 0;
121     for(int i = 1; i <= n; i++) {
122         int temp = 0;
123         for(int j = K - 1; j <= i * K; j++) {
124             temp = (temp + 1ll * fac[j - 1] * f[i][j] % MO * qpow(inv[i], j) % MO * j % MO) % MO;
125         }
126         temp = 1ll * temp * n % MO * inv[i] % MO * C(n, i) % MO;
127         if(i & 1) {
128             ans = (ans + temp) % MO;
129         }
130         else {
131             ans = (ans - temp) % MO;
132         }
133     }
134     printf("%d\n", (ans + MO) % MO);
135     return 0;
136 }
AC代码

 

posted @ 2019-05-29 11:22  huyufeifei  阅读(220)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜