概率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]);
}
别忘了W[i]<=10^9
开long long