• codeforces--698C LRU状压+概率DP


    题目链接:https://codeforces.com/problemset/problem/698/C

    题目大意:有n种节目,每个节目出现的概率为$p_i$,电视的缓存大小为V,当缓存满了后会挤掉出现次数最少的节目,问在$10^{100}$次询问后每个节目存在缓存中的概率。

    Examples

    Input
    3 1
    0.3 0.2 0.5
    Output
    0.3 0.2 0.5 
    Input
    2 1
    0.0 1.0
    Output
    0.0 1.0 
    Input
    3 2
    0.3 0.2 0.5
    Output
    0.675 0.4857142857142857 0.8392857142857143 
    Input
    3 3
    0.2 0.3 0.5
    Output
    1.0 1.0 1.0 

    由于n非常小,所以我们可以直接用二进制枚举缓存中节目的状态,假设dp[sta]表示缓存中存储状态为sta的概率,那么其中第i个1的存在表示第i个节目存在缓存中,我们只需要将每个位数为1的地方做过累加就是每位的最终概率了。

    由于$10^{100}$非常大,所以当n个节目中存在非0概率的个数大于缓存容量时缓存一定会爆,而小于等于的时候不会爆,所以每个非零概率的节目都会存在于缓存中

    所以我们特判一下小于等于的情况,之后就是对爆的情况做状压。

    我们枚举状态sta,当sta中1的个数等于缓存容量的时候就是最终状态了,我们就可以做答案处理,如果sta中1的个数小于缓存容量,那么我们就需要进行状态转移了。也就是对sta中0的元素进行转移即:

    for (int j=1; j<=n; j++)
        if ((i&(1<<(j-1)))==0)
            dp[i|(1<<(j-1))]+=dp[i]*p[j]/zros;//有zros份可以补充,其中j占据了p[j]份

    也就是对该位的0进行补充,但需要注意的是sta有很多个0要补充,所以我们要将这所有的0位置的概率做个累加记为zros,那么补充该位置的0的概率就是p[j]/zros

    那么答案也就很容易出来了

    以下是AC代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const double esp=1e-8;
    #define debug printf("@#$#@$#@%#@1^&^**@#$#@%))#%
    " )
    
    double p[30],dp[1<<21],ans[30];
    
    int main()
    {
        int n,v,cnt=0;
        scanf ("%d%d",&n,&v);
        for (int i=1; i<=n; i++){
            scanf ("%lf",&p[i]);
            if (p[i]>=esp) cnt++;
        }
        if (cnt<=v) {
            for (int i=1; i<=n; i++)
                printf("%.6f%c",p[i]<esp?0.0:1.0,i==n?'
    ':' ');
            return 0;
        }
        dp[0]=1;
        for (int i=0; i<(1<<n); i++){
            int use=0;
            double zros=0;
            for (int j=1; j<=n; j++){
                if (i&(1<<(j-1))) use++;
                else zros+=p[j];
            }
            if (use>v) continue;
            else if (use==v){
                for (int j=1; j<=n; j++)
                    if (i&(1<<(j-1))) 
                        ans[j]+=dp[i];
            }
            else {
                for (int j=1; j<=n; j++)
                    if ((i&(1<<(j-1)))==0)
                        dp[i|(1<<(j-1))]+=dp[i]*p[j]/zros;//有zros份可以补充,其中j占据了p[j]份
            }
        }
        for (int i=1; i<=n; i++)
            printf("%.10f%c",ans[i],i==n?'
    ':' ');
        return 0;
    }
    路漫漫兮
  • 相关阅读:
    【bzoj2006】超级钢琴
    【bzoj4940】这是我自己的发明
    【arc076E】Connected?
    【agc004C】AND Grid
    选举
    几何
    打击目标
    【CF Gym100228】Graph of Inversions
    【CodeChef】Chef and Graph Queries
    大包子玩游戏
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13235695.html
Copyright © 2020-2023  润新知