• 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
    ", (ans + MO) % MO);
    135     return 0;
    136 }
    AC代码
  • 相关阅读:
    一些文件的扩展名
    关于git,从svn转到git
    trousers--------dpkg: 处理软件包 trousers (--configure)时报错
    Ubuntu下运行DrClient以上网
    Ubuntu下的终端命令--复制文件从一个文件夹到另一个文件夹下
    VSCode放大字体的快捷键
    opessl版本过低造成的函数使用错误
    python的基本语法
    ubuntu和windows的解码方式
    ubuntu下强制删除文件夹
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10942703.html
Copyright © 2020-2023  润新知