码迷,mamicode.com
首页 > 其他好文 > 详细

loj#2552. 「CTSC2018」假面

时间:2018-09-03 21:36:38      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:mem   ret   time   lse   print   puts   stat   else   amp   

题目链接

loj#2552. 「CTSC2018」假面

题解

本题严谨的证明了我菜的本质
对于砍人的操作好做找龙哥就好了,blood很少,每次暴力维护一下
对于操作1
\(a_i\)为第i个人存活的概率,\(d_i\)为死掉的概率,\(g_{i,j}\)是除i以外活了j个人的概率
那个选中i人的答案就是
\[a_i\times\sum_{j = 0} ^{k - 1}\frac{g_{i,j}}{j + 1}\]
对于\(g_{i,j}\) ,设\(f_{i,j}\)表示前\(i\)个人有\(j\)个活着的概率,\(f_{i,j}\)可以dp出来
\[f_{i,j} = f_{i - 1,j} \times d_i + f_{i - 1,j - 1} \times a_i\]
我们可以枚举每次\(g_{i,j}\)的i,然后skip掉,这样的复杂度是\(n^3\)
然后就可以前缀后缀背包卷积NTT,或者单点删除的分治做法hhhhhhh
其实这个被背包删除物品可以做O(n)
逆着推一下就好了

代码


#include<cstdio> 
#include<cstring> 
#include<algorithm> 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' || c > '9') c = getchar(); 
    while(c <= '9' && c >= '0') x = x * 10 + c - '0' ,c = getchar(); 
    return x * f; 
} 
const int mod = 998244353; 
const int maxn = 2007; 
long long b[maxn]; 
int n,m ; 
long long p[maxn][maxn]; 
long long inv[maxn]; 
inline int add(int x,int y) { 
    return x + y >= mod ? x + y - mod : x + y; 
} 
inline int fstpow(int x,int k) { 
    int ret = 1; 
    for(;k;k >>= 1,x = 1ll *x * x % mod) 
        if(k & 1) ret = 1ll * ret * x % mod; 
    return ret;  
} 
void solve1(int x,int P) { 
    int rp = 1 + mod - P; 
    for(int i = 0;i <= b[x];++ i) { 
        if(i) p[x][i] = 1ll * p[x][i] * rp % mod; 
        if(i < b[x]) p[x][i] = add(p[x][i] , 1ll * p[x][i + 1] * P % mod) ;  
    } 
} 
int k;
void solve(int k) { 
    static long long f[maxn],g[maxn],h[maxn],t[maxn]; 
    // f存活j个人的概率  
    memset(f,0,sizeof f); 
    f[0] = 1; 
    for(int i = 1;i <= k;++ i) t[i] = read();   
    for(int a,d,i = 1;i <= k;++ i) { 
        a = 1 + mod - p[t[i]][0];
        d = p[t[i]][0];  
        for(int j = i;j >= 0;-- j) 
            f[j] = add((j ? 1ll * f[j - 1] * a % mod : 0) , 1ll * f[j] * d % mod);
    } 
    for(int i = 1;i <= k;++ i) { 
        h[i] = 0; 
        int a = 1 + mod - p[t[i]][0]; 
        if(!p[t[i]][0]) 
            for(int j = 0;j < k;++ j) h[i] = add(h[i],1ll * f[j + 1] * inv[j + 1] % mod); 
        else { 
            int Inv = fstpow(p[t[i]][0],mod - 2); 
            for(int j = 0;j < k;++ j) { 
                g[j] = ((f[j] - (j ? 1ll * g[j - 1] * a % mod : 0) + mod) % mod) * Inv % mod; 
                h[i] = add(h[i],1ll * g[j] * inv[j + 1] % mod); 
            } 
        } 
        h[i] = 1ll * h[i] * a % mod; 
    } 
    for(int i = 1;i <= k;++ i) printf("%d ",h[i]);  
    puts(""); 
} 
main() { 
    //freopen("facel5.in","r",stdin); freopen("w.out","w",stdout); 
    n = read(); 
    for(int i = 1;i <= n;++ i) b[i] = read(), p[i][b[i]] = 1,inv[i] = fstpow(i,mod - 2);
    m = read(); 
    for(int op,i = 1;i <= m;i += 1) { 
        op = read(); 
        if(!op) { 
            int x = read(),u = read(),v = read(); 
            solve1(x,1ll * u * fstpow(v,mod - 2) % mod); 
        } 
        else 
            solve(read());  
    }   
 
    for(int i = 1;i <= n;++ i) { 
        int sum = 0; 
        for(int j = 1;j <= b[i];++ j) 
            sum = add(sum , 1ll * j * p[i][j] % mod) ; 
        printf("%d%c",sum,i != n ? ' ' : '\n'); 
    } 
    return 0; 
} 

loj#2552. 「CTSC2018」假面

标签:mem   ret   time   lse   print   puts   stat   else   amp   

原文地址:https://www.cnblogs.com/sssy/p/9581007.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!