纪中暑假集训 2020.08.12【NOIP提高组】模拟 T2:【五校联考1day2】我想大声告诉你

【五校联考1day2】我想大声告诉你

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% 的数据,n <=100
对于100% 的数据,n <= 2*10^3,1 <= T <= 5,0<= x < y <= 10^9

反思&题解

比赛思路: 一眼概率DP,但直接放弃(因为之前只做过一道概率DP的题,所以对这个知识点还是云里雾里的)
正解思路: 因为每轮不只有一个人被选中和被攻击出局,所以计算每一局不出局的概率有点不现实,不过题目并没有了顺序,所以我们可以将题目转化为 1 1 n n 的排列,之后里面的人依次被淘汰出局。
f [ i ] [ j ] f[i][j] 表示到了第i个人,其后面的人都受到了j次攻击的概率,分两种情况考虑:
1. 如果是被选中出局,那么就是承受了 j 1 j-1 次攻击,且对后面的人全部攻击一次,方程为: f [ i ] [ j ] + = f [ i 1 ] [ j 1 ] ( 1 p ) j 1 f[i][j]+=f[i-1][j-1]*(1-p)^{j-1}
2. 反之就没有攻击的贡献,而且承受了 j 1 j-1 次攻击就出局了,方程为:
f [ i ] [ j ] + = f [ i 1 ] [ j ] [ 1 ( 1 p ) j 1 ] f[i][j]+=f[i-1][j]*[1-(1-p)^{j-1}]
最后对于每个j的答案就是 1 n i = 0 n 1 f [ i ] [ j ] ( 1 p ) j \dfrac{1}{n}\sum^{n-1}_{i=0}f[i][j]*(1-p)^j ,乘 1 n \dfrac{1}{n} 是因为一个人再哪个位置都有可能出现
反思: 概率DP要练几道题巩固一下

CODE

#include<bits/stdc++.h>
using namespace std;
const long long mo=258280327;
long long f[2005][2005],ans,t,num1[2005],num2[2005];
long long power(long long x,long long y)
{
	long long tot=1;
	while (y)
	{
		if (y&1) tot=tot*x%mo;
		y>>=1;
		x=x*x%mo;
	}
	return tot;
}
int main()
{
	int i;
	for (i=0;i<=2000;i++)
		num1[i]=power(i,mo-2);
	scanf("%lld",&t);
	while (t--)
	{
		long long n,x,y;
		scanf("%lld%lld%lld",&n,&x,&y);
		long long p=(1-x*power(y,mo-2)%mo+mo)%mo;
		for (i=0;i<=n;i++)
			num2[i]=power(p,i);
		memset(f,0,sizeof(f));
		f[0][0]=1;
		for (i=1;i<=n;i++)
		{
			int j;
			for (j=0;j<=i;j++)
				f[i][j]=(f[i][j]+f[i-1][j]*((1-num2[j]+mo)%mo)%mo+f[i-1][j-1]*num2[j-1]%mo)%mo;	
		}
		int j;
		for (j=0;j<=n-1;j++)
		{
			ans=0;
			for (i=0;i<=n-1;i++)
				ans=(ans+f[i][j]*num2[j]%mo*num1[n]%mo)%mo;
			printf("%lld ",ans);
		}
		printf("\n");
	}
}

猜你喜欢

转载自blog.csdn.net/CMC_YXY/article/details/107966678