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; 
} 
原文地址:https://www.cnblogs.com/sssy/p/9581007.html