2015 Multi-University Training Contest 5 D(MZL's game)

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值