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代码

 

转载于:https://www.cnblogs.com/huyufeifei/p/10942703.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验二 C#程序设计练习 一、实验目的 1.掌握C#语言的基本语法、控制语句及异常处理。 2.掌握C#类的基本使用方法以及C#语言面向对象的基本特性。 二、实验内容 1.编写一个函数,用于计算1!+2!+3!+4!+5!,在控制台或页面输出运行结果。 2.在控制台或页面输出九九乘法表。 3.输入10个以内的整数,输出该组整数的降序排列,要求采用数组实现。 4.计算两个数的商,在控制台或页面输出结果,要求包含异常处理。 5.定义一个汽车类,该类具有重量和速度属性;再定义一个跑车类,该类继承汽车类的属性,并拥有自己的颜色属性;然后声明一个汽车类的对象和一个跑车类的对象,并把它们的属性输出到控制台上。 6.假设某动物园管理员每天需要给他所负责饲养的狮子、猴子和鸽子喂食。请用一个程序来模拟他喂食的过程。 要求: (1)饲养员喂食时,不同动物执行不同的吃的功能,例如狮子吃肉、猴子吃香蕉、鸽子吃大米等。 (2)饲养员喂动物时,不能使用判断语句判断动物类型。 (3)使用虚方法或抽象方法实现喂养不同动物的多态,不能使用方法重载。 提示:需要建一个动物类,动物类有一个虚的或抽象的吃方法,动物类下面有几个子类,不同的子类重写父类的吃方法。饲养员类提供喂食方法。然后,在Main方法中一一调用吃的方法。 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Add2._1 { class Program { static void Main(string[] args) { int sum = 0; for (int i = 1; i < 6; i++) { int tmp = 1; for (int j = 1; j <= i; j++) { tmp = tmp * j; } sum += tmp; } Console.WriteLine("1!+2!+3!+4!+5!={0}\r\n", sum.ToString()); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值