#概率,dp#JZOJ 4212 我想大声告诉你

题目

(x)和他的(n-1)个朋友,进行(k)轮游戏,每轮等概率选出一个人作为获胜者并退出游戏,
其余在游戏中的人有(p)的概率被迫退出游戏,问对于任意的轮数(k),使小(x)获胜的概率


分析

(dp[i][j])表示前(i)轮有(j)个人退出游戏的概率,
那么

[dp[i][j]=dp[i-1][j-1]*(1-p)^{i-1}+dp[i][j-1]*(1-(1-p)^i) ]

也就是主动退出(前(i-1)轮都在内)或被迫退出(前(i)轮不能都在内)的概率之和。
最后对于单个(k),答案就是

[frac{1}{n}sum_{i=k}^{n-1}dp[k][i]*(1-p)^{k} ]


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int mod=258280327,N=2011;
int n,p,dp[N],inv[N],pw[N],f[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline signed ksm(int x,int y){
	rr int ans=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
	    if (y&1) ans=1ll*ans*x%mod;
	return ans;
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
signed main(){
	inv[0]=inv[1]=pw[0]=1;
	for (rr int i=2;i<N;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	for (rr int Test=iut();Test;--Test){
		n=iut(),p=1ll*iut()*ksm(iut(),mod-2)%mod,dp[0]=1;
		for (rr int i=1;i<=n;++i) pw[i]=1ll*pw[i-1]*(mod-p+1)%mod,dp[i]=0;
		for (rr int i=1;i<=n;++i){
			int ans=0;
			for (rr int j=i-1;j<n;++j)
		        ans=mo(ans,1ll*pw[i-1]*dp[j]%mod);
		    print(1ll*ans*inv[n]%mod),putchar(i==n?10:32);
		    if (i==n) break;
			for (rr int j=i-1;j<n;++j) f[j]=dp[j],dp[j]=0;
			for (rr int j=i;j<n;++j)
			    dp[j]=mo(1ll*dp[j-1]*(mod-pw[i]+1)%mod,1ll*f[j-1]*pw[i-1]%mod);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13509482.html