zoukankan      html  css  js  c++  java
  • 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;
    }
    路漫漫兮
  • 相关阅读:
    磁盘分区,fdisk,gdisk,开机自动挂载,swap分区,修复文件系统,备份文件
    进程脱离窗口运行,僵尸、孤儿进程
    top命令、kill命令
    进程状态
    rpm包、挂载、yum命令
    DRF源码分析
    forms组件源码
    Django CBV源码分析
    魔法方法
    鸭子类型
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13235695.html
Copyright © 2011-2022 走看看