1. 程式人生 > >#2552. 「CTSC2018」假面

#2552. 「CTSC2018」假面

一個 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」假面