• loj#2552. 「CTSC2018」假面


    题目链接

    loj#2552. 「CTSC2018」假面

    题解

    本题严谨的证明了我菜的本质
    对于砍人的操作好做找龙哥就好了,blood很少,每次暴力维护一下
    对于操作1
    (a_i)为第i个人存活的概率,(d_i)为死掉的概率,(g_{i,j})是除i以外活了j个人的概率
    那个选中i人的答案就是

    [a_i imessum_{j = 0} ^{k - 1}frac{g_{i,j}}{j + 1} ]

    对于(g_{i,j}) ,设(f_{i,j})表示前(i)个人有(j)个活着的概率,(f_{i,j})可以dp出来

    [f_{i,j} = f_{i - 1,j} imes d_i + f_{i - 1,j - 1} imes a_i ]

    我们可以枚举每次(g_{i,j})的i,然后skip掉,这样的复杂度是(n^3)
    然后就可以前缀后缀背包卷积NTT,或者单点删除的分治做法hhhhhhh
    其实这个被背包删除物品可以做O(n)
    逆着推一下就好了

    代码

    
    #include<cstdio> 
    #include<cstring> 
    #include<algorithm> 
    inline int read() { 
    	int x = 0,f = 1; 
    	char c = getchar(); 
    	while(c < '0' || c > '9') c = getchar(); 
    	while(c <= '9' && c >= '0') x = x * 10 + c - '0' ,c = getchar(); 
    	return x * f; 
    } 
    const int mod = 998244353; 
    const int maxn = 2007; 
    long long b[maxn]; 
    int n,m ; 
    long long p[maxn][maxn]; 
    long long inv[maxn]; 
    inline int add(int x,int y) { 
    	return x + y >= mod ? x + y - mod : x + y; 
    } 
    inline int fstpow(int x,int k) { 
    	int ret = 1; 
    	for(;k;k >>= 1,x = 1ll *x * x % mod) 
    		if(k & 1) ret = 1ll * ret * x % mod; 
    	return ret;  
    } 
    void solve1(int x,int P) { 
    	int rp = 1 + mod - P; 
    	for(int i = 0;i <= b[x];++ i) { 
    		if(i) p[x][i] = 1ll * p[x][i] * rp % mod; 
    		if(i < b[x]) p[x][i] = add(p[x][i] , 1ll * p[x][i + 1] * P % mod) ;  
    	} 
    } 
    int k;
    void solve(int k) { 
    	static long long f[maxn],g[maxn],h[maxn],t[maxn]; 
    	// f存活j个人的概率  
    	memset(f,0,sizeof f); 
    	f[0] = 1; 
    	for(int i = 1;i <= k;++ i) t[i] = read(); 	
    	for(int a,d,i = 1;i <= k;++ i) { 
    		a = 1 + mod - p[t[i]][0];
    		d = p[t[i]][0];  
    		for(int j = i;j >= 0;-- j) 
    			f[j] = add((j ? 1ll * f[j - 1] * a % mod : 0) , 1ll * f[j] * d % mod);
    	} 
    	for(int i = 1;i <= k;++ i) { 
    		h[i] = 0; 
    		int a = 1 + mod - p[t[i]][0]; 
    		if(!p[t[i]][0]) 
    			for(int j = 0;j < k;++ j) h[i] = add(h[i],1ll * f[j + 1] * inv[j + 1] % mod); 
    		else { 
    			int Inv = fstpow(p[t[i]][0],mod - 2); 
    			for(int j = 0;j < k;++ j) { 
    				g[j] = ((f[j] - (j ? 1ll * g[j - 1] * a % mod : 0) + mod) % mod) * Inv % mod; 
    				h[i] = add(h[i],1ll * g[j] * inv[j + 1] % mod); 
    			} 
    		} 
    		h[i] = 1ll * h[i] * a % mod; 
    	} 
    	for(int i = 1;i <= k;++ i) printf("%d ",h[i]); 	
    	puts(""); 
    } 
    main() { 
    	//freopen("facel5.in","r",stdin); freopen("w.out","w",stdout); 
    	n = read(); 
    	for(int i = 1;i <= n;++ i) b[i] = read(), p[i][b[i]] = 1,inv[i] = fstpow(i,mod - 2);
    	m = read(); 
    	for(int op,i = 1;i <= m;i += 1) { 
    		op = read(); 
    		if(!op) { 
    			int x = read(),u = read(),v = read(); 
    			solve1(x,1ll * u * fstpow(v,mod - 2) % mod); 
    		} 
    		else 
    			solve(read());  
    	}	
     
    	for(int i = 1;i <= n;++ i) { 
    		int sum = 0; 
    		for(int j = 1;j <= b[i];++ j) 
    			sum = add(sum , 1ll * j * p[i][j] % mod) ; 
    		printf("%d%c",sum,i != n ? ' ' : '
    '); 
    	} 
    	return 0; 
    } 
    
  • 相关阅读:
    有效的数独
    两个数组的交集
    单值二叉树
    go实现二叉树
    合并两个有序链表
    重塑矩阵
    CompantScan 今天碰到问题记录
    报错:expected at least 1 bean which qualifies as autowire candidate(Spring Bean 无法注入)
    The attempt was made from the following location: com.ruoyi.framework.config.ResourcesConfig.corsFilter(ResourcesConfig.java:57)
    2022年官网下安装ZooKeeper最全版与官网查阅方法
  • 原文地址:https://www.cnblogs.com/sssy/p/9581007.html
Copyright © 2020-2023  润新知