• 模拟4题解 T1礼物


     T1


    题目描述

    夏川的生日就要到了。作为夏川形式上的男朋友,季堂打算给夏川买一些生 日礼物。

    商店里一共有种礼物。夏川每得到一种礼物,就会获得相应喜悦值Wi(每种 礼物的喜悦值不能重复获得)。

    每次,店员会按照一定的概率Pi(或者不拿出礼物),将第i种礼物拿出来。 季堂每次都会将店员拿出来的礼物买下来。没有拿出来视为什么都没有买到,也 算一次购买。

    众所周知,白毛切开都是黑的。所以季堂希望最后夏川的喜悦值尽可能地高。

    求夏川最后最大的喜悦值是多少,并求出使夏川得到这个喜悦值,季堂的期 望购买次数。

    输入格式

    第一行,一个整数N,表示有N种礼物。

    接下来N行,每行一个实数Pi和正整数Wi,表示第i种礼物被拿出来的概率和 可以获得喜悦值。

    输出格式

    第一行,一个整数表示可以获得的最大喜悦值。

    第二行,一个实数表示获得这个喜悦值的期望购买次数,保留3位小数。

    样例

    样例输入

    3
    0.1 2
    0.2 5
    0.3 7

    样例输出

    14
    12.167

    数据范围与提示

    对于10%的数据,N = 1
    对于30%的数据,N ≤ 5
    对于100%的数据,N ≤ 20 ,0 < Wi ≤ 10^9 ,0 < Pi ≤ 1且∑Pi ≤ 1


      [概率与期望][状压DP]

    n<=20所以很显然的状态压缩,

    定义f[s]为状态为s时的还要走的期望步数

    则f[(1<<n)-1]为 0,f[0]为所求

    倒着推

    f[i]=Σf[j]*q[k]+(1-Σq[k])*f[i]+1;

    i 当前状态,j 转移过来的状态,Σ为 枚举i中的某一个0由1转移过来,k为之一位

    显然i可由 1,以q[k]的概率买到i,和以1-Σq[k]的概率恰好碰到到已有的或没有拿出来(此时转移由i过来)的状态组成;

    对于  101010

    可由 111010,101110,101011 这三种状态+(1-Σq[k]绿色的1的概率)不买k的状态,转移过来

    那为什么正着推不行?

    当正着推时,状态转移方程中1-Σq[k]无含义,故不成立;

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 const double eps=1e-12;
     5 double p[22];
     6 int n;
     7 long long sum=0;
     8 double f[1<<21];
     9 int cot(int x)
    10 {
    11     int ret=1;
    12     while(x&1)
    13     {
    14         x>>=1;
    15         ret++;
    16     }
    17     return ret;
    18 }
    19 
    20 int main()
    21 {
    22     scanf("%d",&n);
    23     for(int i=1;i<=n;i++)
    24     {
    25         int x;
    26         scanf("%lf%d",&p[i],&x);
    27         if(p[i]<eps)continue;
    28         sum+=x;
    29     }
    30     if(n==1)
    31     {
    32         printf("%lld
    ",sum);
    33         double ans=1/p[1];
    34         printf("%.3lf",ans);
    35     }
    36     else
    37     {
    38         int mx=1<<n;
    39         f[mx-1]=0; 
    40         for(int i=mx-2;i>=0;i--)
    41         {    
    42             double tot=0.0,fs=0.0;
    43             int t;
    44             for(int k=i;k<mx;k+=(1<<(t-1)))
    45             {
    46                 t=cot(k);
    47                 fs+=f[i|(1<<(t-1))]*p[t];
    48                 tot+=p[t];
    49             }
    50             f[i]=(fs+1.0)/tot;
    51         }
    52         printf("%lld
    %.3lf",sum,f[0]);
    53     }
    54 }
    View Code
    愿你在迷茫时,记起自己的珍贵。
  • 相关阅读:
    C#自带的Version判断版本号的大小
    通过iis启动服务,会产生C:/inetpub/logs/logsFile产生大量的日志,定期清理
    C# 需要引用MySql.Data.dll,请在Nuget安装最新稳定版本,如果有版本兼容问题请先删除原有引用 (SqlSugar)
    C# sqlsugar依赖引用报错的问题解决
    Python 函数
    Python 迭代器与生成器
    Python 循环语句
    Python 条件控制
    Python 编程第一步
    Python 列表复制
  • 原文地址:https://www.cnblogs.com/casun547/p/11197524.html
Copyright © 2020-2023  润新知