礼物(倒着求期望)[20190716NOIP模拟测试4]

A. 礼物

 
题目类型:传统 评测方式:文本比较
内存限制:256 MiB 时间限制:1000 ms 标准输入输出

题目描述

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

商店里一共有种礼物。夏川每得到一种礼物,就会获得相应喜悦值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

Yu-shi 说正着求概率,倒着求期望

s表示状态,s'表示之前的状态,p[i]表示买到 i 礼物的概率,g表示啥都没买到的概率,f[s]表示状态s的期望次数(表示到(1<<n)-1的期望步数,f[(1<<n)-1]=0)

 状转方程为

    $f[s]=sum f[s’]*p[i]+(sum p[i]+g)*f[s]+1$

  移项得 $f[s]=(sum f[s’]*p[i]+1))/(1-sum p[i]-g)$

 代码代码:

#include<iostream>
#include<cstdio>
using namespace std;
int n,num[1<<25],c[25];
long long ans;
double a[25],f[1<<25];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf%d",&a[i],&c[i]),ans+=c[i];
    for(int i=1;i<=n;i++) num[(1<<i-1)]=i;
    for(int i=(1<<n)-2;i>=0;i--){
        double x=0.0;
        for(int j=1;j<=n;j++){
            int w=1<<(j-1);
            if(!(i&w)){
                x+=a[num[w]];
                f[i]+=f[i^w]*a[num[w]];
            }
            
        }
        f[i]+=1.0;
        f[i]/=x;
    }
    printf("%lld
%.3lf
",ans,f[0]);
}
$Will$ $Be$ $The$ $King$
原文地址:https://www.cnblogs.com/heoitys/p/11198984.html