题意
n n 个人个操作 , , 第个人有 mi m i 滴血 , , 有两种操作
以 p p 的概率使掉 1 1 点血
给出 k k 个人从这些人中等概率地选出 1 1 个求每个人被选中的概率
最后求每个人剩余血量的期望
题解
考虑怎么求每个人剩余的血的期望
用 pu[i] p u [ i ] 表示 u u 剩余点血的概率 ⇒Eu=∑mii=0ipu[i] ⇒ E u = ∑ i = 0 m i i p u [ i ]
这个 pu p u 是可以用背包维护的 ( ( 而且非常好理解初值 pu[mu]=1) p u [ m u ] = 1 )
p′u[0]=pu[0]+pu[1]∗p p u ′ [ 0 ] = p u [ 0 ] + p u [ 1 ] ∗ p
p′u[i]=pu[i]∗(1−p)+pu[i+1]∗p,i∈[1,mu] p u ′ [ i ] = p u [ i ] ∗ ( 1 − p ) + p u [ i + 1 ] ∗ p , i ∈ [ 1 , m u ]
操作 1 1 就用上面的维护即可
考虑怎么处理操作 2 2
实际上操作只需要知道每个人活下来的概率即可 , , 即
对于 k k 个人中的每个人用简单的数学知识可以得到选中的概率是
fu[i] f u [ i ] 表示除了 u u 之外只有个人活着的概率
枚举另外一个人 v, v , 可以得到
于是乎对于每一个人做一遍这样的 dp d p 即可
复杂度
O(Qm+Cn3)
O
(
Q
m
+
C
n
3
)
显然过不了
考虑如果知道还活着任意 i i 个人的概率和 pxu, p x u , 能不能知道 fu[i]? f u [ i ] ?
显然是可以的可以发现上面那个
dp
d
p
没有人的限制
,
,
所以可以倒过来
因为这个 v v 是随意的所以有
当 pxu=1 p x u = 1 时 fu[i]=g[i+1] f u [ i ] = g [ i + 1 ]
g g 可以通过一个的 dp d p 求出
对于每一个人只要再 O(n) O ( n ) 逆转移一下即可
总时间复杂度 O(Qm+Cn2) O ( Q m + C n 2 )
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=205,P=998244353;
typedef int arr[N];
typedef long long ll;
int n,m,q;arr f,g,w,px,inv,p[N];
int Inv(int x){return x<N?inv[x]:(ll)(P-P/x)*Inv(P%x)%P;}
inline int pls(int a,int b){return a+=b,a<P?a:a-P;}
inline int sub(int a,int b){return a-=b,a<0?a+P:a;}
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
sd(n);
fp(i,1,n)sd(w[i]),p[i][w[i]]=1;inv[1]=1;
fp(i,2,N-1)inv[i]=(ll)(P-P/i)*inv[P%i]%P;
sd(q);int op,x,a,b,tp=0;
while(q--){
sd(op);
if(op){
sd(m);fp(i,1,m)sd(x),px[i]=sub(1,p[x][0]),g[i]=0;g[0]=1;
fp(i,1,m)fd(j,i,0)g[j]=((j?(ll)px[i]*g[j-1]%P:0ll)+(ll)sub(1,px[i])*g[j])%P;
fp(i,1,m){
if(!px[i]){we(0);continue;}
if(px[i]==1)fp(j,0,m-1)f[j]=g[j+1];
else{
x=Inv(sub(1,px[i]));f[0]=(ll)g[0]*x%P;
fp(j,1,m-1)f[j]=(ll)sub(g[j],(ll)f[j-1]*px[i]%P)*x%P;
}
fp(j,0,m-1)tp=pls(tp,(ll)f[j]*inv[j+1]%P);
we((ll)px[i]*tp%P);tp=0;
}sr[++C]='\n';
}else{
sd(x),sd(a),sd(b);
a=(ll)a*Inv(b)%P,b=sub(1,a);
p[x][0]=pls(p[x][0],(ll)p[x][1]*a%P);
fp(i,1,w[x])p[x][i]=((ll)p[x][i+1]*a+(ll)p[x][i]*b)%P;
}
}
fp(i,1,n){
tp=0;
fp(j,1,w[i])tp=pls(tp,(ll)j*p[i][j]%P);
we(tp);
}
return Ot(),0;
}
出题人说这是一道NOIP中档题