• BZOJ5340: [Ctsc2018]假面


    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} imes 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("");
    }
    
  • 相关阅读:
    校验函数
    声明
    主程序(开始检查)
    活代码LINQ——09
    活代码LINQ——08
    活代码LINQ——07
    活代码LINQ——06
    活代码LINQ——05
    活代码LINQ——04
    活代码LINQ——03
  • 原文地址:https://www.cnblogs.com/suika/p/10264151.html
Copyright © 2020-2023  润新知