#2552. 「CTSC2018」假面
阿新 • • 發佈:2018-05-16
一個 c++ HR span != getchar %d efi end
2552. 「CTSC2018」假面
一道“普及難度”DP題。。。然而考場上沒想出來。
一堆人題解裏說“只要會期望和逆元都能AC”,我ssfd
還是在看完題解之後照著題解打的
大概就是設$f[i][j]$表示第$i$個人血量為$j$的概率
然而1號操作的轉移就是$f[i][j]\leftarrow f[i][j](1-p)+f[i][j+1]p$。
二號操作就比較麻煩了。
可以枚舉每個人,設$g[i]$為存活$i$個人的概率(不包括枚舉的人),那麽轉移就是$g[i]\leftarrow g[i]dead[x]+g[i-1]alive[x]$
這個人被選的概率為$alive[x]*\sum_{i=0}^{k-1}\frac{g[i]}{i+1}$
其中$alive[x]$是$x$存活的概率,$dead[x]$是$x$死亡的概率
顯然$dead[x]=f[x][0],alive[x]=1-f[x][0]$
那麽得到一個二號操作一次$O(n^3)$的優秀算法。
得到70分的好成績。
然後想想優化
好像每兩次產生的$g$只會有兩處不同(刪一個人再加一個人可以得到新的$g$)
那麽可以先不枚舉,直接算出總的$g$數組
再每次刪一個
$g‘[i]=g[i]dead[x]+g[i-1]alive[x]$
化成
$g[i]=\frac{g‘[i]-g[i-1]*alive[x]}{dead[x]}$
然後就可以$O(n)$求出每次的$g$數組辣
完結撒花
我還是太菜了。
#include<bits/stdc++.h>
#define il inline
#define vd void
#define mod 998244353
typedef long long ll;
il int gi(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0' &&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
il vd exgcd(ll a,ll b,ll&x,ll&y){
if(b==0)x=1,y=0;
else{
exgcd(b,a%b,y,x);
y-=a/b*x;
}
}
std::map<int,int>M;
il ll inv(ll a){
if(M.find(a)!=M.end())return M[a];
ll A=a,B=mod;
ll x,y;
exgcd(A,B,x,y);
x=(x%mod+mod)%mod;
M[a]=x;
return x;
}
ll f[201][102];
ll alive[201],dead[201];
ll g[201],gg[201],a[201],m[201];
int main(){
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
freopen("output.out","w",stdout);
#endif
int n=gi();
for(int i=1;i<=n;++i)f[i][m[i]=gi()]=1;
int Q=gi(),op,id,u,v;
for(int i=1;i<=Q;++i){
op=gi();
if(op==0){
id=gi(),u=gi(),v=gi();
int p=1ll*u*inv(v)%mod;
f[id][0]=(f[id][0]+1ll*f[id][1]*p%mod)%mod;
for(int j=1;j<=m[id];++j)f[id][j]=(f[id][j]*(mod+1-p)%mod+f[id][j+1]*p%mod)%mod;
}else{
for(int j=1;j<=n;++j)alive[j]=(mod+1-f[j][0])%mod;
for(int j=1;j<=n;++j)dead[j]=f[j][0];
int tot=gi();
for(int j=1;j<=tot;++j)a[j]=gi();
for(int j=1;j<=n;++j)g[j]=0;
g[0]=1;
for(int j=1;j<=tot;++j){
for(int k=j;k;--k)g[k]=(g[k-1]*alive[a[j]]+g[k]*dead[a[j]]%mod)%mod;
g[0]=g[0]*dead[a[j]]%mod;
}
for(int x=1;x<=tot;++x){
if(dead[a[x]]==0)for(int j=0;j<tot;++j)gg[j]=g[j+1];
else{
gg[0]=1;
for(int j=1;j<=tot;++j)if(x!=j)gg[0]=gg[0]*dead[a[j]]%mod;
for(int j=1;j<tot;++j)gg[j]=(g[j]-gg[j-1]*alive[a[x]]%mod+mod)%mod*inv(dead[a[x]])%mod;
}
ll ans=0;
for(int k=1;k<=tot;++k)ans+=gg[k-1]*inv(k)%mod;
printf("%lld ",alive[a[x]]*(ans%mod)%mod);
}
puts("");
}
}
for(int i=1;i<=n;++i){
int ans=0;
for(int j=1;j<=m[i];++j)ans=(ans+j*f[i][j]%mod)%mod;
printf("%d ",ans);
}
puts("");
return 0;
}
#2552. 「CTSC2018」假面