Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 236 Accepted Submission(s): 142
Problem Description
MZL has n cute boys.They are playing a game♂.The game will run in turn
First,System choose an alive player x randomly.Player x will be out of the game.
Then player x will attack all alive players in the game
When a player is attacked,1−p is the probability of he still lives,p is the probability of he dies
Now mzl wants to know:the probability of one player be out of the game and be attacked k times
You need to print the probability mod 258280327 for every k from 0 to n-1
According to Fermat Theory,xy mod 258280327=x*(y258280325) mod 258280327
p will be given in a special way
Input
The first line of the input contains a single number T, the number of test cases.
Next T lines, each line contains three integer n,x,y.p=xy
T≤5, n≤2∗103 0≤x≤109 x+1≤y≤109.
It is guaranteed that y and 258280327 are coprime.
Output
T lines, every line n numbers: the ans from 0 to n-1
Sample Input
2
3 33 100
9 23 233
Sample Output
172186885 210128265 223268793
229582513 70878931 75916746 175250440 21435537 57513225 236405985 111165243 115953819
Hint
for case 1:
The probability of you live and not be attacked is 1/3
The probability of you live and be attacked for one time is:
(2/3)*(0.33*0.67+0.67*0.67*(1/2))=8911/30000
来自:https://blog.youkuaiyun.com/kyleyoung_ymj/article/details/51725370
题意:有nn个人在玩游戏,每轮游戏随机选取一个活着的人,他会对其他活着的每个人进行一次攻击,然后退出游戏.
当一个人被攻击时,他有pp的概率会死亡,有1−p1−p的概率仍然活着.
对所有k∈[0,n)k∈[0,n),求一个人出局时恰好被攻击kk次的概率.
首先容易设计出一个朴素的dp:
令dp[i][j]表示已经进行了i轮,并且还有jj个人存活的概率.这样子转移是O(n)的,而且不好优化.
这时候有一种非常机智的做法,强行规定每轮依次从1~n选出人退出游戏,如果选出的人已经死亡则直接跳到下一轮.
又有一种非常奇妙的状态定义,设dp[i][j](j<i)dp[i][j](j<i)表示要选出第ii个人时,前面有jj个人活着退出游戏的概率,即此时i~n中活着的人都受到了j次攻击.
考虑i−1是否活着就可以得到下面的转移方程:
dp[i][j]=dp[i−1][j−1]⋅(1−p)^j−1+dp[i−1][j]⋅(1−(1−p)^j).
dp[i][j]=dp[i−1][j−1]⋅(1−p)^j−1+dp[i−1][j]⋅(1−(1−p)^j).
其中第一种情况是i−1在j−1次攻击中存活下来,第二种情况是i−1没有在j次攻击中存活下来.
于是可以通过预处理1−p的幂使得转移的复杂度降为O(1).
然而还有一个最终答案是什么的问题.
我们这样转换游戏规则之后dp[i][k]⋅(1−p)kdp[i][k]⋅(1−p)k就表示第i个被选到的人恰好被攻击k次后退出游戏的概率,对i求和之后就表示所有人恰好被攻击k次后退出游戏的概率,但因为题目要求的是对一个人的概率,所以要再除掉一个n,即ans(k)=∑(1->n)(dp[i][k]⋅(1−p)^k)/n.
代码
const int N=2e3+5,mod=258280327;
int pow_p[N],dp[N][N];
int fast_mod_pow(int a,int b){
int res=1;
for(;b;b>>=1,a=1ll*a*a%mod)
if(b&1)res=1ll*res*a%mod;
return res;
}
int inv(int x){
return fast_mod_pow(x,mod-2);
}
void solve(){
int n,x,y;
scanf("%d%d%d",&n,&x,&y);
x=y-x;
int p=1ll*x*inv(y)%mod;
pow_p[0]=1;
for(int i=1;i<=n;++i)
pow_p[i]=1ll*pow_p[i-1]*p%mod;
dp[1][0]=1;
for(int i=2;i<=n;++i){
for(int j=0;j<i;++j){
dp[i][j]=1ll*dp[i-1][j-1]*pow_p[j-1]%mod;
if(j<i-1)dp[i][j]=((dp[i][j]+1ll*dp[i-1][j]*(1-pow_p[j]))%mod+mod)%mod;
}
}
for(int k=0,inv_n=inv(n);k<n;++k){
int ans=0;
for(int i=1;i<=n;++i)
ans=(ans+1ll*dp[i][k]*pow_p[k])%mod;
printf("%d%c",(int)(1ll*ans*inv_n%mod)," \n"[k==n-1]);
}
}
int main(){
int cas;
scanf("%d",&cas);
while(cas--)solve();
return 0;
}