题目:https://loj.ac/problem/2552
70 分就是 f[i][j] 表示第 i 个人血量为 j 的概率。这部分是 O( n*Q ) 的;g[i][j][0/1] 表示询问的人中,前/后 i 个人,存活 j 个人的概率。做 g[ ][ ] 是 n^2 的,算答案是 n3 的。
考虑 g[ i ] 表示询问的人中有 i 个存活的概率。因为每个人加入 g[ ] 的顺序无关,所以可以每次 O(n) 地从g[ ] 里剔除第 i 个人的贡献。
令第 i 个人不存活的概率是 u ,存活的概率是 v 。
当初的转移是 g[ i ] * u -> g'[ i ] , g[ i ] * v -> g'[ i+1 ] ,所以现在可以倒着做:g[ i ] = g'[ i+1 ] / v , g'[ i ] -= g[ i ] ,或者正着做:g[ i ] = g'[ i ] / u , g'[ i+1 ] -= g[ i ] * v 。
发现如果 u=0 ,那么 g[ i ] 的值只体现在了 g'[ i+1 ] 里;所以倒着做。如果 v=0 就正着做。
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } const int N=205,M=105,mod=998244353; int upt(int x){while(x>=mod)x-=mod;while(x<0)x+=mod;return x;} int pw(int x,int k) {int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret;} int n,a[N],f[N][M],g[N],tp[N],h[N],q[N],inv[N]; int main() { n=rdn(); inv[1]=1; for(int i=2;i<=n;i++)inv[i]=(ll)upt(-mod/i)*inv[mod%i]%mod; for(int i=1,d;i<=n;i++) { a[i]=rdn();f[i][a[i]]=1;} int Q=rdn(),op,x,u,v; while(Q--) { op=rdn(); if(!op) { x=rdn();u=rdn();v=rdn(); u=(ll)u*pw(v,mod-2)%mod; for(int j=1;j<=a[x];j++) { f[x][j-1]=(f[x][j-1]+(ll)f[x][j]*u)%mod; f[x][j]=(ll)f[x][j]*upt(1-u)%mod; } if(!f[x][a[x]])a[x]--; } else { x=rdn(); int tl=0; for(int i=1;i<=x;i++) q[++tl]=rdn(); g[0]=1;for(int i=1;i<=tl;i++)g[i]=0; for(int i=1;i<=tl;i++) { u=f[q[i]][0]; v=upt(1-u); for(int j=i;j>=0;j--) { g[j]=(ll)g[j]*u%mod; if(j)g[j]=(g[j]+(ll)g[j-1]*v)%mod; } } for(int i=1;i<=tl;i++) { u=f[q[i]][0]; v=upt(1-u); memcpy(tp,g,sizeof g); if(!u) { int iv=pw(v,mod-2); for(int j=tl-1;j>=0;j--) { h[j]=(ll)tp[j+1]*iv%mod; tp[j]=upt((tp[j]-(ll)u*h[j])%mod); } } else { int iu=pw(u,mod-2); for(int j=0;j<tl;j++) { h[j]=(ll)tp[j]*iu%mod; tp[j+1]=upt((tp[j+1]-(ll)v*h[j])%mod); } } int ans=0; for(int j=0;j<tl;j++) ans=(ans+(ll)h[j]*v%mod*inv[j+1])%mod; printf("%d ",ans); } puts(""); } } for(int i=1;i<=n;i++) { int ans=0; for(int j=0;j<=a[i];j++) ans=(ans+(ll)j*f[i][j])%mod; printf("%d ",ans); } puts(""); return 0; }