BZOJ5340: [Ctsc2018]假面
阿新 • • 發佈:2019-01-14
ont pri 計算 define return urn max namespace bzoj
BZOJ5340: [Ctsc2018]假面
https://lydsy.com/JudgeOnline/problem.php?id=5340
分析:
- 背包,只需要求\(g_{i,j}\)表示強制活第\(i\)個人一共活了\(j\)個人的概率,\(f_j\)表示活了\(j\)個人的概率 。
- 這個東西有\(g_{i,j}=f_{j}-g_{i,j+1}\times p_i/(1-p_i)\)
- 轉移即可,有小細節。
- \(p_i\)可能為\(0\)使得沒有逆元,不過此時答案一定為\(0\)。
- 在計算第\(i\)個人血量為\(j\)的概率時,\(0\)的轉移比較特殊 。
代碼:
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> using namespace std; typedef long long ll; #define mod 998244353 #define N 205 #define MAXH 105 int n,Q,id[N],inv[N]; ll h[N],P[N][MAXH],old[MAXH],num[N],f[N][N],g[N][N]; ll qp(ll x,ll y) {ll re=1;for(;y;y>>=1,x=x*x%mod)if(y&1)re=re*x%mod; return re;} ll INV(ll x) {return qp(x,mod-2);} int main() { int i,op,j; scanf("%d",&n); for(i=1;i<=n;i++) inv[i]=INV(i); for(i=1;i<=n;i++) scanf("%lld",&h[i]),P[i][h[i]]=1; scanf("%d",&Q); for(;Q--;) { scanf("%d",&op); if(op==0) { int x,u,v; scanf("%d%d%d",&x,&u,&v); ll tmp=ll(u)*INV(v)%mod; for(i=h[x]+1;i>=0;i--) old[i]=P[x][i]; for(i=h[x];i>=0;i--) { if(i) P[x][i]=(old[i]*(1-tmp)+old[i+1]*tmp)%mod; else P[x][i]=(P[x][i]+old[i+1]*tmp)%mod; } }else { int k; scanf("%d",&k); for(i=1;i<=k;i++) scanf("%d",&id[i]); for(i=1;i<=k;i++) num[i]=(mod+1-P[id[i]][0])%mod; memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); f[0][0]=1; for(i=1;i<=k;i++) { for(j=k;j>=0;j--) { f[i][j]=f[i-1][j]*(1-num[i])%mod; if(j) f[i][j]=(f[i][j]+f[i-1][j-1]*num[i])%mod; } } for(i=1;i<=k;i++) { if(!num[i]) {printf("0 "); continue;} g[i][k]=f[k][k]; ll tmp=(1-num[i])*INV(num[i])%mod; for(j=k-1;j>=1;j--) { g[i][j]=(f[k][j]-g[i][j+1]*tmp)%mod; } ll re=0; for(j=1;j<=k;j++) re=(re+g[i][j]*inv[j])%mod; printf("%lld ",(re+mod)%mod); } puts(""); } } for(i=1;i<=n;i++) { ll re=0; for(j=1;j<=h[i];j++) re=(re+j*P[i][j])%mod; printf("%lld ",(re+mod)%mod); } puts(""); }
BZOJ5340: [Ctsc2018]假面