• CCPC2020 威海 E.So Many Possibilities...


    CCPC2020 威海 E.So Many Possibilities...

    E

    题意:n 个怪物,第 i 个怪物有血量 (a_i) 。 m 次操作,每次从还活着(血量>0)的怪物中等概率随机挑选一个使其血量减一,问 m 次操作后期望杀死多少只怪物。 (n le 15, m,a_i le 100, sum a_i > m)

    key:概率 dp

    如果知道哪些死了,也知道操作数,那么没有针对最终死亡的怪物的操作次数也是可以知道的,并且实际上针对谁并不重要。也就是说,对于一个操作序列,我们只需要知道哪些操作是针对最终死亡的即可,剩下的可以直接乘一个系数。

    (g[i][S]) 表示对于 (j in S) 的所有怪物一共砍 i 刀且都不砍死的方案数。等价于 i 个石头染色,第 (j) 种颜色小于等于 (a_j-1) 块石头的方案数。暴力枚举 S 然后 dp 是 (O(2^nnm^2)) ,边 dfs 边 dp 就变成 (O(2^nm^2)) 。这个就是那个系数,即活着的怪物的贡献。

    现在考虑死掉的怪物的贡献。记 (S) 表示生死状态,0 为生, 1 为死。 (f[i][S]) 表示砍 i 刀使得生死状态为 S 的概率,(sum[S]) 表示 (jin S) 的所有怪物血量之和,那么其中 (i-sum[S]) 次操作是砍在活着的怪物上的,在这里贡献是 1 (因为当前只考了死掉的怪物)。那么第 i+1 刀有两种情况:

    1. 砍死一只新怪物,设其为 j 。那么 (i-sum[S]) 中应该有 (a_j-1) 次操作砍在 j 上。贡献是 ({i-sum[S] choose a_j-1} / |ar S|)
    2. 没有砍死。那么当前贡献是 (1/|ar S|)

    要除以 (|ar S|) 是因为第 i+1 次操作的随机性。复杂度是 (O(2^nnm))

    最终答案是 (sum_{S} f[m][S]*g[m-sum[S]][ar S]*|S|)

    于是总复杂度是 (O(2^n(n+m)m))

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef long double LD;
    typedef pair<LL,LL> pii;
    typedef pair<double, double> pdd;
    const int SZ = 50100;
    const double INF = 1e10 + 10;
    const int mod = 998244353;
    const LD eps = 1e-8;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
    	if(flag) n = -n;
    	return n;
    }
    
    
    int n,m,a[117];
    double f[117][SZ],C[110][110];
    double g[117][110];
    double G[110][SZ];
    int sum[SZ];
    int NT[SZ];
    
    // 0:live  1:dead
    
    void print(int x) {
        for(int i = 0;i < n;i ++)
            printf("%d",x>>i&1);
        printf("");
    }
    
    
    void dfs(int d, int S, int nt) {
        if(d == n) {
            for(int i = 0;i <= m;i ++) {
                G[i][S] = g[nt][i];
            }
            return ;
        }
    
        for(int i = 0;i <= m;i ++) {
            for(int j = 0;j < a[d+1] && j <= i;j ++)
                g[nt+1][i] += g[nt][i-j] * C[i][j];
        }
        dfs(d+1,S,nt+1); // d is live
        for(int i = 0;i <= m;i ++) {
            g[nt+1][i] = 0;
        }
        dfs(d+1,S^(1<<d),nt);
    }
    
    void init() {
        C[0][0] = 1;
        for(int i = 1;i <= 100;i ++) {
            C[i][0] = 1;
            for(int j = 1;j <= i;j ++) {
                C[i][j] = C[i-1][j]+C[i-1][j-1];
            }
        }
    }
    
    bool isok(int i,int S) {
        int nS = (1<<n)-S-1;
        return i >= sum[S] && sum[nS] - NT[S] >= i-sum[S];
    }
    
    int main() {
        init();
        n = read(),m = read();
        for(int i = 1;i <= n;i ++) a[i] = read();
        for(int S = 0;S < (1<<n);S ++) {
            for(int i = 0;i < n;i ++) {
                if(S>>i&1)
                    sum[S] += a[i+1];
            }
        }
    
        g[0][0] = 1;
        dfs(0,0,0);
    
    
        for(int S = 0; S < (1<<n);S ++) { // S,t: dead   ns,nt: live
            int nt = 0;
            for(int i = 0;i < n;i ++) if(!(S>>i&1)) nt ++;
            NT[S] = nt;
        }
    
    
        // 0:live  1:dead
        double ans = 0;
        f[0][0] = 1;
        for(int S = 0; S < (1<<n);S ++) { // 1,t: dead   0,nt: live
            int nt = 0;
            for(int i = 0;i < n;i ++) if(!(S>>i&1)) nt ++;
            int t = n - nt;
            int nS = (1<<n)-S-1;
            for(int i = 0;i < m;i ++) {
                if(isok(i,S)) {
                    double x = 1;
                    for(int j = 0;j < n;j ++) {
                        if(!(S>>j&1)) { // j is alive, make it dead
                            if(isok(i+1,S^(1<<j))) {
                                double k = C[i-sum[S]][a[j+1]-1] / nt;
                                f[i+1][S^(1<<j)] += f[i][S] * k;
                            }
                        }
                    }
                    if(isok(i+1,S)) {
                        f[i+1][S] += f[i][S] / nt;
                    }
                } else {
                    f[i][S] = 0;
                }
            }
            if(m >= sum[S]) {
                ans += f[m][S] * G[m-sum[S]][S] * t;
            }
        }
        printf("%.10f
    ",(double)ans);
    }
    
    /*
    15 100
    7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
    
    */
    
    
  • 相关阅读:
    Read-Copy Update Implementation For Non-Cache-Coherent Systems
    10 华电内部文档搜索系统 search04
    10 华电内部文档搜索系统 search05
    lucene4
    10 华电内部文档搜索系统 search01
    01 lucene基础 北风网项目培训 Lucene实践课程 索引
    01 lucene基础 北风网项目培训 Lucene实践课程 系统架构
    01 lucene基础 北风网项目培训 Lucene实践课程 Lucene概述
    第五章 大数据平台与技术 第13讲 NoSQL数据库
    第五章 大数据平台与技术 第12讲 大数据处理平台Spark
  • 原文地址:https://www.cnblogs.com/dqsssss/p/13882193.html
Copyright © 2020-2023  润新知