jzoj 4212.【五校联考1day2】我想大声告诉你 dp

本文探讨了一个涉及概率的游戏策略,目标是计算在特定条件下,玩家遭受特定次数攻击后出局的概率。通过构建数学模型,分析了游戏过程中的概率转移,并提供了解决问题的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

2
3 40 100
9 32 1049

Sample Output

172186885 92980918 16529941
229582513 163885050 39458156 102374877 116777758 216371874 55544199 95860736 8136787

Data Constraint

对于60%60\%60%的数据,n&lt;=100n &lt;=100n<=100
对于100%100\%100%的数据,n&lt;=2∗103,1&lt;=T&lt;=5,0&lt;=x&lt;y&lt;=109n &lt;= 2* 10^3,1 &lt;= T &lt;= 5,0&lt;= x &lt; y &lt;= 10^9n<=21031<=T<=50<=x<y<=109

分析:
我们按人的出局顺序构造一个序列,显然任何一个排列都是有可能的。
但是我们只需要知道关键人物的位置,其他位置是不同的人,只要不是关键人物,都是等价的。
f[i][j]f[i][j]f[i][j]表示第iii个人到第nnn个人都还没有出局,而且这些人都被攻击了jjj次的方案。
显然有两种转移,设p=x/yp=x/yp=x/y
f[i][j]=f[i−1][j−1]∗(1−p)j+f[i−1][j]∗(1−(1−p)j)f[i][j]=f[i-1][j-1]*(1-p)^j+f[i-1][j]*(1-(1-p)^j)f[i][j]=f[i1][j1](1p)j+f[i1][j](1(1p)j)
后面这个表示第i−1i-1i1个人被前面的人给淘汰了,无法造成贡献;前面这个人没有被淘汰,对当前造成贡献。
ans[j]ans[j]ans[j]表示被攻击jjj次的概率,那么就是f[i][j]f[i][j]f[i][j]的和除以nnn,因为关键人物的位置是随机的。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define LL long long

const int maxn=2007;
const LL mod=258280327;

using namespace std;

int n,T;
LL x,y,p;
LL f[maxn][maxn],ans[maxn],power[maxn];

LL ksm(LL x,LL y)
{
	if (y==0) return 1;
	LL c=ksm(x,y/2);
	c=(c*c)%mod;
	if (y&1) c=(c*x)%mod;
	return c;
}

int main()
{
	scanf("%d",&T);
	while (T--)
	{
		scanf("%d%lld%lld",&n,&x,&y);
		p=x*ksm(y,mod-2)%mod;
        power[0]=1;
		for (int i=1;i<n;i++) power[i]=power[i-1]*(1+mod-p)%mod;
		memset(f,0,sizeof(f));
		f[1][0]=1;
		for (int i=2;i<=n;i++)
		{
			for (int j=0;j<n;j++)
			{
				f[i][j]=(f[i][j]+f[i-1][j]*((1+mod-power[j])%mod)%mod)%mod;
				if (j>0) f[i][j]=(f[i][j]+f[i-1][j-1]*power[j]%mod)%mod;
			}
		}
		memset(ans,0,sizeof(ans));
		for (int j=0;j<n;j++)
		{
			for (int i=1;i<=n;i++)
			{
				ans[j]=(ans[j]+f[i][j])%mod;
			}
			ans[j]=ans[j]*ksm(n,mod-2)%mod;
		}
		for (int i=0;i<n;i++) printf("%lld ",ans[i]);
		printf("\n");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值