抽鬼牌(poker)

题目描述

小海喜欢和小鸟玩抽鬼牌,规则如下:小鸟每次有n张牌,其中有m张鬼牌;小海一次抽出一张牌,如果不是鬼牌则移除这张牌,否则小海就输了;当只剩下m张鬼牌时小海赢。

     因为小海永远赢不了,所以小鸟修改了规则。如果小海输了,那她可以把鬼牌放回去并继续进行一轮游戏(非鬼牌保持不变),直到她赢为止。每一轮游戏,小鸟都会获得一个愉悦值。假设这轮游戏小海抽到k张非鬼牌,小鸟的愉悦值为(k+1)^q。为了更好的欣赏小海的颜艺,小鸟想知道她的期望愉悦值(mod 998244353)。

输入

一行3个数n,m,q

输出

一个数表示答案

样例输入

4 2 2

456 123 6

样例输出

665496246

32740446

提示

 数据范围

10% n=m+1

另外10% n<=8

另外20% q=0;

另外20% n<=1e3

另外 10% q=1

另外 20% n<=1e5

100%  m<=n  n<=1e6  q<=10

设f[i]表示还剩i张牌的期望愉悦值。

$f[i]=\frac{m}{i}(f[i]+1)+\sum_{j<i}{\frac{i-m}{i}*\frac{i-m-1}{i-1}*…*\frac{j-m-1}{j+1}*\frac{m}{j}*(f[j]+(i-j+1)^q})$

将f[i]挪到左边整理一下可以得到

$f[i]=\frac{m}{i-m}(\frac{m}{i}+\sum_{j<i}{\frac{i-m}{i}*\frac{i-m-1}{i-1}*…*\frac{j-m-1}{j+1}*\frac{m}{j}*(f[j]+(i-j+1)^q}))$

这东西可以跑$O(n^2)$的dp了

考虑f[i-1]的转移式子和f[i]的转移式子的区别。

$(k+1)^q=\sum k^i*C(q,i)$

可以$O(nq^2)$DP

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define MOD 998244353
 4 #define M 1000010
 5 int fac[M], inv[M], f[M];
 6 int v[M];
 7 int C[20][20];
 8 int main() {
 9     int n, m, q;
10     scanf("%d%d%d", &n, &m, &q);
11     fac[0] = 1;
12     for(int i = 1; i <= n; ++ i) {
13         fac[i] = 1ll * fac[i - 1] * i % MOD;
14     }
15     inv[0] = inv[1] = 1;
16     for(int i = 2; i <= n; ++ i) {
17         inv[i] = 1ll * (MOD - MOD / i) * inv[MOD % i] % MOD;
18     }
19     for(int i = 0; i <= q; ++ i) v[i] = 1;
20     for(int i = 0; i <= 10; ++ i) C[i][0] = 1;
21     for(int i = 1; i <= 10; ++ i) {
22         for(int j = 1; j <= i; ++ j) {
23             C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
24             if(C[i][j] >= MOD) C[i][j] -= MOD;
25         }
26     }
27     int o = 0;
28     for(int i = m + 1; i <= n; ++ i) {
29         for(int j = q; j >= 0; -- j) {
30             for(int k = 0; k < j; ++ k) {
31                 v[j] += 1ll * v[k] * C[j][k] % MOD;
32                 if(v[j] >= MOD) v[j] -= MOD;
33             }
34             v[j] = 1ll * v[j] * (i - m) % MOD * inv[i] % MOD;
35         }
36         o = 1ll * o * (i - m) % MOD * inv[i] % MOD;
37         f[i] = (1ll * v[q] + o + 1ll * m * inv[i] % MOD) * i % MOD * inv[i - m] % MOD;
38         o += 1ll * f[i] * m % MOD * inv[i] % MOD;
39         if(o >= MOD) o -= MOD;
40         for(int j = 0; j <= q; ++ j) {
41             v[j] += 1ll * m * inv[i] % MOD;
42             if(v[j] >= MOD) v[j] -= MOD;
43         }
44     }
45     printf("%d\n", f[n]);
46 }

 

posted @ 2018-08-07 10:10  iamunstoppable  阅读(1233)  评论(0编辑  收藏  举报