zoukankan      html  css  js  c++  java
  • [CTSC2018]假面

    I.[CTSC2018]假面

    期望第一题,居然能独立做出来。

    首先这个数据范围明显是暗示我们一个\(O(Qm+Cn^2)\)的算法可以过去。

    我们设\(pos_{i,j}\)表示敌人\(i\)剩余血量为\(j\)的概率。

    则当使用一个“锁定”技能后,就相当于对\(pos_i\)做了一个背包,单次复杂度\(O(m_i)\)

    再考虑“结界”技能。

    我们设一个\(f_i\),表示该技能使用时,恰有\(i\)个人有血的概率。这个可以\(O(n^2)\)背包搞出来。

    然后,再对于每个\(i\)\(O(n)\)地从这个背包中“删掉”它。

    需要注意的是,当\(i\)一定有血的时候,这个“删掉”操作与其它情况不同,需要特判一下。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=998244353;
    int ksm(int x,int y){
    	int z=1;
    	for(;y;y>>=1,x=1ll*x*x%mod)if(y&1)z=1ll*z*x%mod;
    	return z;
    }
    int n,lim[210],q,pos[210][110],p[210],f[210],g[210],inv[210];
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d",&lim[i]),pos[i][lim[i]]=1;
    	for(int i=1;i<=n;i++)inv[i]=ksm(i,mod-2);
    	scanf("%d",&q);
    	for(int qwq=1,a,b,c,d;qwq<=q;qwq++){
    		scanf("%d",&a);
    		if(a==0){
    			scanf("%d%d%d",&b,&c,&d),c=1ll*c*ksm(d,mod-2)%mod,d=(mod+1-c)%mod;
    			(pos[b][0]+=1ll*pos[b][1]*c%mod)%=mod;
    			for(int i=1;i<=lim[b];i++)pos[b][i]=(1ll*pos[b][i]*d+1ll*pos[b][i+1]*c)%mod;
    		}else{
    			scanf("%d",&b);
    			for(int i=1;i<=b;i++)scanf("%d",&p[i]);
    			for(int i=0;i<=b;i++)f[i]=0;
    			f[0]=1;
    			int zero=0;
    			for(int i=1;i<=b;i++){
    				c=pos[p[i]][0],d=(mod+1-c)%mod;
    				if(!c){zero++;continue;}
    				for(int j=i-zero;j>=0;j--){
    					f[j]=1ll*f[j]*c%mod;
    					if(j)(f[j]+=1ll*f[j-1]*d%mod)%=mod;
    				}
    			}
    //			printf("P:");for(int i=1;i<=b;i++)printf("%d ",pos[p[i]][0]);puts("");
    //			printf("F:");for(int i=0;i<=b;i++)printf("%d ",f[i]);puts("");
    			for(int i=1;i<=b;i++){
    				c=pos[p[i]][0],d=(mod+1-c)%mod;
    				c=ksm(c,mod-2);
    				for(int j=0;j<=b-zero;j++)g[j]=f[j];
    				if(c){
    					for(int j=0;j<b-zero;j++){
    						g[j]=1ll*g[j]*c%mod;
    						(g[j+1]+=mod-1ll*g[j]*d%mod)%=mod;
    					}					
    				}
    //				printf("%d:GGG",i);for(int j=0;j<b;j++)printf("%d ",g[j]);puts("");
    				int res=0;
    				for(int j=0;j<=b-zero;j++)(res+=1ll*inv[j+zero+(c!=0)]*g[j]%mod)%=mod;
    				printf("%d ",1ll*res*d%mod);
    			}puts("");
    		}
    	}
    	for(int i=1;i<=n;i++){
    		int res=0;
    		for(int j=0;j<=lim[i];j++)(res+=1ll*pos[i][j]*j%mod)%=mod;
    		printf("%d ",res);
    	}
    	return 0;
    }
    

  • 相关阅读:
    中文转数字
    半角全角互转
    sql快速查记录数
    杀进程批处理
    线程基本用法
    sql游标用法示例
    BUGFREE的使用
    SQL常用函数
    ASP.NET 2.0 下的验证码控件
    经典sql语句
  • 原文地址:https://www.cnblogs.com/Troverld/p/14610831.html
Copyright © 2011-2022 走看看