【模擬賽】遊戲
阿新 • • 發佈:2021-11-10
考慮 \(DP\) 。
如果兩人都miss,則沒有意義,所以有:
令轉移 \(A\) 的概率為:\(p_a=\frac{p(1-q)}{1-(1-p)(1-q)}\),
轉移 \(B\) 的概率為:\(p_b=\frac{q(1-p)}{1-(1-p)(1-q)}\),
轉移 \(C\) 的概率為:\(p_c=1-p_a-p_b\)。
則:\(dp[i][j]=p_a\times dp[i-1][j]+p_b\times dp[i][j-1]+p_c\times dp[i-1][j-1]\)。直接 \(DP\) 是 \(O(nm)\) 的。
因為轉移的概率與當前血量無關,於是我們可以用一個非常經典的套路,把整個 \(DP\)
注意實現時處理到 \(Bob\) 量為1時即可,最後 \(Alice\) 一次打敗 \(Bob\) 。
code
#include<bits/stdc++.h> using namespace std; const int N=5e6,P=998244353,inv100=828542813; int T,n,m,fac[N+5],inv[N+5],p,q,_p,_q; int pa[N+5],pb[N+5],pc[N+5],sum[N+5]; int KSM(int a,int b) { int ret=1; while(b) { if(b&1) ret=1ll*ret*a%P; a=1ll*a*a%P;b>>=1ll; } return ret; } int C(int a,int b) {return 1ll*fac[a]*inv[b]%P*inv[a-b]%P;} int main() { fac[0]=inv[0]=1;for(int i=1; i<=N; i++) fac[i]=1ll*fac[i-1]*i%P; inv[N]=KSM(fac[N],P-2); for(int i=N-1; i>=1; i--) inv[i]=1ll*(i+1)*inv[i+1]%P; scanf("%d",&T); while(T--) { scanf("%d%d%d%d",&n,&m,&p,&q); _p=100-p;_q=100-q; p=1ll*p*inv100%P;q=1ll*q*inv100%P; _p=1ll*_p*inv100%P;_q=1ll*_q*inv100%P; int hv=KSM((1-(1ll*_p*_q%P)+P)%P,P-2); pa[0]=pb[0]=pc[0]=sum[0]=1; pa[1]=1ll*_p*q%P*hv%P; pb[1]=1ll*p*_q%P*hv%P; pc[1]=1ll*p*q%P*hv%P; sum[1]=1ll*(sum[0]+1ll*C(m,1)*pa[1]%P)%P; for(int i=2; i<=max(n,m); i++) pa[i]=1ll*pa[i-1]*pa[1]%P, pb[i]=1ll*pb[i-1]*pb[1]%P, pc[i]=1ll*pc[i-1]*pc[1]%P, sum[i]=(sum[i-1]+1ll*C(m+i-1,i)*pa[i]%P)%P; //sum表示選擇不超過i個A的方案數。 int ans=0; for(int i=0; i<min(n,m); i++)//列舉C的個數 { int tmp=1ll*pc[i]*pb[m-i-1]%P; ans+=1ll*tmp*C(m-1,i)%P*sum[n-i-1]%P,ans%=P; } printf("%d\n",1ll*p*hv%P*ans%P); } return 0; }