jzoj4212. 【五校联考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

题解

这题真的很有趣,比赛时玩一玩很好。
我打死也不告诉你我玩完后没有预处理导致时超并且比赛时间不够导致爆0

60%
这档部分分很不错,只是与100分相去甚远。
我们为了好表示,出局代表小R被选出去,淘汰表示小R被攻击而淘汰。
看到题目我们考虑f[i,j,0…1]表示这个小R被攻击了i次后,不出局或出局,剩下j个人的概率。
转移就稍微要注意一下了。
首先我们考虑从i-1转移到i。
那么我们枚举i-1状态时剩下的人k以及当前i状态时剩下的人j。
注意i-1状态是已经有一个人出局但未攻击。
而这个i状态是上一个人(非小R)已经攻击完且小R未淘汰。
所以转移方程大致为:
f [ i , j , 0 ] + = f [ i − 1 , k , 0 ] ∗ p k − j ∗ ( 1 − p ) j ∗ c ( j − 1 , k − 1 ) ; f[i,j,0]+=f[i-1,k,0]*p^{k-j}*(1-p)^j*c(j-1,k-1); f[i,j,0]+=f[i1,k,0]pkj(1p)jc(j1,k1);
什么意思呢?
就是上一个状态攻击有k-j个人淘汰,j个人存活。
由于每个人都不相同,所以我们还要考虑组合数。
就是在剩下除了小R的人中任意选j-1个人存活。
这个转移是 O ( n 3 ) O(n^3) O(n3)
然后接下来我们还要维护这个f[i,j,1].
f [ i , j , 1 ] : = f [ i , j + 1 , 0 ] / ( j + 1 ) ; f[i,j,1]:=f[i,j+1,0]/(j+1); f[i,j,1]:=f[i,j+1,0]/(j+1);
然后再把小R出局后的情况给更新f[i,j,0]即可。
f [ i , j , 0 ] : = f [ i , j + 1 , 0 ] ∗ j / ( j + 1 ) ; f[i,j,0]:=f[i,j+1,0]*j/(j+1); f[i,j,0]:=f[i,j+1,0]j/(j+1);
这样就可以做到 O ( n 3 ) O(n^3) O(n3),注意预处理。

当然,如果想把这个方法利用前缀和之类的优化来优化似乎是可以的。
但是我不会。
所以我们考虑换一种思路来想。

100%
我们考虑把每个人出局或淘汰的顺序来进行DP
我们发现,由于每次出局的人是随意的,每次淘汰的人也是不定的。
所以我们就不必关心不同的人的不同淘汰或出局顺序
设f[i,j]表示当前1 ~ i的顺序的人都淘汰或出局(i+1 ~ n的顺序人不理会),i+1 ~ n的人受到j次攻击的概率。
所以我们就考虑怎么从前面的状态转移到i这个位置。
分类讨论

1、当i这个人是出局的,那么这个i必然是在经过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} f[i,j]+=f[i1,j1](1p)j1
2、当i这个人是淘汰的,那么这个i必然是在前面j次攻击时其中一个挂掉的,并且不会对后面攻击。
f [ i , j ] + = f [ i − 1 , j ] ∗ ( 1 − ( 1 − p ) j ) f[i,j]+=f[i-1,j]*(1-(1-p)^{j}) f[i,j]+=f[i1,j](1(1p)j)
然后就转移完了。
很巧妙,对吗?
初始化 f [ 0 , 0 ] : = 1 ; f[0,0]:=1; f[0,0]:=1;

然后统计答案。
我们考虑枚举小R是第几个挂掉的。
那么答案即为: ∑ i = 0 n − 1 ∑ j = 0 n − 1 f [ i , j ] ∗ ( 1 − p ) j / n \sum_{i=0}^{n-1}\sum_{j=0}^{n-1}f[i,j]*(1-p)^j/n i=0n1j=0n1f[i,j](1p)j/n
表示小R是在i+1这个位置出局的概率,由于之前小R都没有出局,那么小R必然是正常出局。
后面这个/n表示小R在i+1这个位置出局的概率。
时间是 O ( n 2 ) O(n^2) O(n2)的。

代码

60%

{$inline on}
var
        i,j,k,l,n,m,t:longint;
        x,y,p,q,answer:int64;
        mo:int64=258280327;
        f,g:array[0..2001,0..2001,0..1] of int64;
        op,oq:array[0..2000] of int64;
        jc:array[0..2000] of int64;
        c:array[-1..2000,-1..2000] of int64;
function qsm(a,b:int64):int64;inline;
var
        t,y:int64;
begin
        t:=1;
        y:=a;
        while b<>0 do
        begin
                if(b and 1)=1 then
                        t:=(t*y) mod mo;
                y:=(y*y) mod mo;
                b:=b shr 1;
        end;
        exit(t);
end;
function cc(m,n:longint):int64;inline;
begin
        if m=n then exit(1);
        if m=0 then exit(1);
        if n=0 then exit(1);
        exit(jc[n]*qsm(jc[m]*jc[n-m] mod mo,mo-2) mod mo);
end;
begin
        jc[0]:=1;
        jc[1]:=1;
        for i:=2 to 2000 do
        begin
                jc[i]:=jc[i-1]*i mod mo;
        end;
        c[0,0]:=1;
        for i:=0 to 2000 do
        begin
                c[0,i]:=1;
                for j:=1 to 2000 do
                begin
                        c[j,i]:=(c[j,i-1]+c[j-1,i-1]) mod mo;
                end;
        end;
        for i:=0 to 2000 do c[0,i]:=1;
        readln(t);
        while t>0 do
        begin
                dec(t);
                readln(n,x,y);
                fillchar(f,sizeof(f),0);
                p:=x*qsm(y,mo-2) mod mo;
                q:=(y-x)*qsm(y,mo-2) mod mo;
                op[0]:=1;
                oq[0]:=1;
                for i:=1 to 2000 do
                begin
                        op[i]:=op[i-1]*p mod mo;
                        oq[i]:=oq[i-1]*q mod mo;
                end;
                f[0,n-1,0]:=(n-1)*qsm(n,mo-2) mod mo;
                f[0,n-1,1]:=qsm(n,mo-2) mod mo;
                for i:=1 to n-1 do
                begin
                        for j:=1 to n do
                        begin
                                for k:=j to n do
                                begin
                                        //l:=cc(j-1,k-1);
                                        f[i,j,0]:=(f[i,j,0]+f[i-1,k,0]*op[k-j] mod mo*oq[j] mod mo*c[j-1,k-1]) mod mo;
                                end;
                        end;
                        for j:=0 to n-1 do
                        begin
                                f[i,j,1]:=f[i,j+1,0]*qsm(j+1,mo-2) mod mo;
                        end;
                        for j:=1 to n-1 do
                        begin
                                f[i,j,0]:=f[i,j+1,0]*j mod mo*qsm(j+1,mo-2) mod mo;
                        end;
                end;
                for i:=0 to n-1 do
                begin
                        answer:=0;
                        for j:=0 to n do
                        begin
                                answer:=(answer+f[i,j,1]) mod mo;
                        end;
                        write(answer,' ');
                end;
                writeln;
        end;
end.

100%

{$inline on}
var
        i,j,k,l,n,m,t:longint;
        x,y,p,q,answer,ny:int64;
        mo:int64=258280327;
        f,g:array[0..2001,-1..2001] of int64;
        op,oq,ok:array[0..2000] of int64;
        jc:array[0..2000] of int64;
        c:array[-1..2000,-1..2000] of int64;
function qsm(a,b:int64):int64;inline;
var
        t,y:int64;
begin
        t:=1;
        y:=a;
        while b<>0 do
        begin
                if(b and 1)=1 then
                        t:=(t*y) mod mo;
                y:=(y*y) mod mo;
                b:=b shr 1;
        end;
        exit(t);
end;
function cc(m,n:longint):int64;inline;
begin
        if m=n then exit(1);
        if m=0 then exit(1);
        if n=0 then exit(1);
        exit(jc[n]*qsm(jc[m]*jc[n-m] mod mo,mo-2) mod mo);
end;
begin
        jc[0]:=1;
        jc[1]:=1;
        for i:=2 to 2000 do
        begin
                jc[i]:=jc[i-1]*i mod mo;
        end;
        c[0,0]:=1;
        for i:=0 to 2000 do
        begin
                c[0,i]:=1;
                for j:=1 to 2000 do
                begin
                        c[j,i]:=(c[j,i-1]+c[j-1,i-1]) mod mo;
                end;
        end;
        for i:=0 to 2000 do c[0,i]:=1;
        readln(t);
        while t>0 do
        begin
                dec(t);
                readln(n,x,y);
                fillchar(f,sizeof(f),0);
                p:=x*qsm(y,mo-2) mod mo;
                q:=(y-x)*qsm(y,mo-2) mod mo;
                op[0]:=1;
                oq[0]:=1;
                ok[0]:=1;
                for i:=1 to 2000 do
                begin
                        op[i]:=op[i-1]*p mod mo;
                        oq[i]:=oq[i-1]*q mod mo;
                        ok[i]:=ok[i-1]*q mod mo;;
                end;
                f[0,0]:=1;
                for i:=1 to n do
                begin
                        for j:=0 to i do
                        begin
                                if j>0 then
                                f[i,j]:=(f[i,j]+f[i-1,j-1]*ok[j-1] mod mo) mod mo;
                                f[i,j]:=(f[i,j]+f[i-1,j]*(1-ok[j]+mo) mod mo) mod mo;
                        end;
                end;
                ny:=qsm(n,mo-2);
                for i:=0 to n-1 do
                begin
                        answer:=0;
                        for j:=0 to n-1 do
                        begin
                                answer:=(answer+f[j,i]) mod mo;
                        end;
                        answer:=answer*ok[i] mod mo*ny mod mo;
                        write(answer,' ');
                end;
                writeln;
        end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值