Description
因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一些人,小R 自然也参加了。
这个游戏有n 个人参加,每一轮随机选出一个还没有出局的人x,接着x 会出局。x 在出局之后剩下的人会受到一次攻击,每一个人在遭到攻击之后会有p 的概率出局。(注意遭到攻击出局的人是不能攻击剩下的人的)
在所有人都出局之后,遭受攻击次数等于特定值的人能够成为胜者。所以现在小R 想要知道对于每一个0 <= k < n,自己恰好在遭受k 次攻击之后出局的概率是多少。(这里的出局指的不是被攻击出局)
注意在这题中,所有数值的运算在模258280327 的意义下进行。
Input
第一行输入一个正整数T 表示数据组数。
对于每一组数据输入仅一行三个数n, x, y,表示在这组数据中有n 个人参赛,p = x/y。保证y 和258280327 互质。
Output
对于每组数据,输出一行n 个整数,表示对于k = 0到n - 1 的概率在模258280327 意义下的值。
Sample Input
23 40 1009 32 1049
Sample Output
172186885 92980918 16529941229582513 163885050 39458156 102374877 116777758 216371874 55544199 95860736 8136787
Data Constraint
对于60% 的数据,n <=100
对于100% 的数据,n <= 2* 10^3,1 <= T <= 5,0<= x < y <= 10^9
分析
我想大声挖倍内听!吔X啦梁非凡!
内!我要炒内啊!
↑这是我看到题目一瞬间脑补的
这题意有个等价的方法
就是第i次游戏选第i个人,第i个人未出局就出局,并且使后面i+1~n个人有p概率出局,已出局就不管
其实是一样的
那么可以写DP
设f[i][j]为选第i个人前,1~i-1有j个人被点出局了
那么状态转移显然:
1、f[i+1][j+1]+=f[i][j]*((y-x)/y)^(j+1)(i被点掉了)
2、f[i+1][j]+=f[i][j]*(x/y)^(j)(i刚好没了)
最后求和除个n就行
#include <iostream> #include <cstdio> #include <memory.h> using namespace std; typedef long long ll; const int P=258280327; const int N=2e3+10; int T,n; ll x,y,ny[N],f[N][N]; ll Power(ll x,ll y) {ll ans=1;for (;y;y>>=1,(x*=x)%=P) if (y&1) (ans*=x)%=P;return ans;} int main() { for (scanf("%d",&T);T;T--) { scanf("%d%lld%lld",&n,&x,&y); ll cy=Power(y,P-2);ny[0]=1;memset(f,0,sizeof f);f[1][0]=1; for (int i=1;i<=n;i++) ny[i]=ny[i-1]*(y-x)%P*cy%P; for (int i=1;i<n;i++) for (int j=0;j<i;j++) if (f[i][j]) (f[i+1][j+1]+=f[i][j]*ny[j+1]%P)%=P,(f[i+1][j]+=f[i][j]*(1-ny[j]+P)%P)%=P; for (int i=0;i<n;i++) { ll lans=0; for (int j=1;j<=n;j++) (lans+=f[j][i])%=P; printf("%lld ",lans*Power(n,P-2)%P); } printf("\n"); } }
原文地址:https://www.cnblogs.com/mastervan/p/10316836.html