zoukankan      html  css  js  c++  java
  • [CTSC2018] 假面

    link

    $solution:$

    考虑暴力 $dp$ 。

    设 $f_{i,j}$ 表示第 $i$ 个人还有 $j$ 血量的概率。因为 $血量leq100$ 所以这个转移不会超时。

    最后直接按照这个值算最后期望即可。

    而结界技能 $g_{i,j}$ 表示前 $i$ 个人有 $j$ 人存活的概率,则 $g_{i,j}=g_{i-1,j} imes f_{i,0}+g_{i-1,j-1} imes (1-f_{i,0})$ 。因为每次处理第 $x$ 个人将即可。每次查询时间复杂度 $O(n^3)$ 。

    但是这样会超时,考虑如何将一次操作做到 $O(n^2)$  。

     因为这个式子可以人的顺序是无序的, $g_{i,j}=g_{i-1,j} imes f_{i,0}+g_{i-1,j-1} imes (1-f_{i,0})$ ,所以可以倒退 $g$ 式。每次查询时间复杂度 $O(n^2)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define int long long
    #define mod 998244353
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=201;
    int f[MAXN]    [MAXN],n;
    int ksm(int a,int b){
        int ans=1;
        while(b){
            if(b&1) ans*=a,ans%=mod;
            a*=a,a%=mod;
            b>>=1;
        }return ans;
    }
    int q,a[MAXN],cur[MAXN];
    int Mod(int x){return ((x%mod)+mod)%mod;}
    int calc(int x){
        int ans=0;
        for(int i=1;i<=a[x];i++){
            ans+=i*f[x][i];
            ans%=mod;
        }return ans;
    }
    int p[MAXN],inv[MAXN];
    int Num,g[MAXN],k[MAXN];
    void Calc_init(){
        k[0]=0;
        for(int i=1;i<=Num;i++) k[++k[0]]=p[i];
        memset(g,0,sizeof(g));g[0]=1;
        for(int i=1;i<=Num;i++){
            for(int j=Num;j>=0;j--) {
                if(j!=0) g[j]=Mod(g[j]*f[k[i]][0])+Mod(g[j-1]*Mod((1-f[k[i]][0]))),g[j]=Mod(g[j]);
                else g[j]=g[j]*f[k[i]][0],g[j]=Mod(g[j]);
            }
        }
        return;
    }
    int G[MAXN];
    int Calc(int x){
        memset(G,0,sizeof(G));
        int ans=0;
        if(f[x][0]==0){
            for(int i=1;i<=Num;i++) ans+=g[i]*inv[i],ans=Mod(ans);
            return ans;
        }
        G[0]=1;
        for(int i=1;i<=Num;i++) if(p[i]!=x) G[0]*=f[p[i]][0],G[0]=Mod(G[0]);
        for(int i=0;i<Num;i++){
            if(i>0) G[i]=Mod(Mod(g[i]-(Mod((Mod(1-f[x][0]))*G[i-1])))*ksm(f[x][0],mod-2));
            ans+=G[i]*inv[i+1];ans=Mod(ans);
        }return Mod(ans*Mod(1-f[x][0]));
    }
    void debug(){
        printf("debug
    ");
        for(int i=1;i<=n;i++){
            for(int j=0;j<=a[i];j++) printf("%lld ",f[i][j]);
            printf("
    ");
        }printf("===============
    ");
        return;
    }
    signed main(){
        //freopen("3.in","r",stdin);
        //freopen("3.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++) inv[i]=ksm(i,mod-2);
        for(int i=1;i<=n;i++) f[i][(a[i]=read())]=1;
        q=read();
        while(q--){
            int opt=read();
            if(opt==0){
                int id=read(),u=read(),v=read();
                int Inv=(u*ksm(v,mod-2))%mod;
                memset(cur,0,sizeof(cur));
                cur[0]=Mod(f[id][0]+f[id][1]*Inv);
                for(int i=1;i<=a[id];i++) cur[i]=Mod(f[id][i]*Mod(1-Inv) +f[id][i+1]*Inv);
                for(int i=0;i<=a[id];i++) f[id][i]=cur[i];
            }else{
                int k=read();Num=k;
                for(int i=1;i<=k;i++) p[i]=read();
                Calc_init();
                for(int i=1;i<=k;i++) printf("%lld ",Calc(p[i]));printf("
    ");
            }
        }
        for(int i=1;i<=n;i++) printf("%lld ",calc(i));printf("
    ");
        return 0;
    }/*
    3
    1 2 3
    3
    0 2 1 1
    0 2 1 1
    1 3 1 2 3
    */
    View Code
  • 相关阅读:
    把握人生12种财富:让商人更自信
    英语谚语的汉译
    心胸有多大,事业才可能有多大
    想成领袖?先瞄准老板身边的位置
    绝对挑战:如何来提高自己的影响力?
    送给创业的朋友:落入坑洞的猎人
    跨越危机,塑造完美的职业生涯(三)
    如果一个男人真的爱你
    跨越危机,塑造完美的职业生涯(一)
    来自最伟大推销员的成功金句
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/10847671.html
Copyright © 2011-2022 走看看