$$AVICII$$

概率DP 礼物

2019.7.16

  hzoi noip模拟T1

    发现自己就是个**,一看到概率DP就犯难。硬着头皮打暴力,连精度也不会卡,尽管知道概率DP都倒着推,emmm。。。

  首先,要明确题面,是有P[i]的几率买到此礼物,而一次只买到一件。然后,显然,P[i]>0,所以最大喜悦值为sum

  10%

    print 1/P[1]

  100%

    n<=20 考虑状压,dp[state]表示从dp[(1<<N)-1]到此的期望,初始状态为dp[(1<<N)-1]=0 。

   有转移式

    dp[state]=Σ{(dp[state]+1)*P[s+1]}(买到已买到的)+(dp[state]+1)*(1-ΣP[i])(啥都没买到)+Σ{(dp[state^(1<<s)]+1)*P[s+1]}

   然后移项即可

  

#include<cstdio>
#include<iostream>
#define MAXN 25
using namespace std;
int W[MAXN];
double P[MAXN];
int N;
double mei=1.0;
double dp[(1<<20)+1];
long long sum;
int main(){
//    freopen("da.in","r",stdin);
    scanf("%d",&N);
    for(int i=1;i<=N;++i){
        scanf("%lf%d",&P[i],&W[i]);
        mei-=P[i];    
        sum+=W[i];
    }
    int lim=(1<<N)-1;
    dp[0]=0;
    double lin,xi;
    for(int state=lim-1;state>=0;--state){
//        printf("orz state=%d\n",state);
        xi=1.0;
        for(int s=0;s<N;++s)
            if(!((1<<s)&state))
                dp[state]+=(dp[state^(1<<s)]+1)*P[s+1];
            else{
                xi-=P[s+1];
                dp[state]+=P[s+1];    
            }
        dp[state]+=mei;
        dp[state]/=(xi-=mei);
//        printf("xi=%lf\ndp[%d]=%lf\n",xi,state,dp[state]);
    }
    printf("%lld\n%.3lf\n",sum,dp[0]);
}
View Code

  别忘了W[i]<=10^9

  开long long

posted @ 2019-07-16 15:57  bootpuss  阅读(152)  评论(0编辑  收藏  举报