【[SCOI2008]獎勵關】
阿新 • • 發佈:2019-01-01
又抄了一篇題解
要涼了要涼了,開學了我還什麼都不會
文化課涼涼,NOIP還要面臨爆零退役的歷史程序
這道題挺神的,期望+狀態壓縮
我們設\(dp[i][S]\)表示在第\(i\)天前,撿的寶物狀態為\(S\)到第\(K\)天結束的期望收益是多少
於是我們的答案是\(dp[1][0]\),也就是第一天前(就是沒開始)什麼寶物也沒有到結束的期望是多少
期望倒著推,我們的初始狀態就是\(dp[k+1]=\{0\}\)
之後對於一個狀態\(dp[i][S]\)
在第\(i\)天\(m\)種寶物出現的概率都是\(1/m\)
所以列舉每一種寶物\(j\),如果這個寶物的前提條件被\(S\)包含
就有
\[dp[i][S]+=max(dp[i+1][S|(1<<(j-1))]+val[j],dp[i+1][S])*1/m\]
就是就算可以選擇這個寶物的話,我們也兩種選擇拿或者不拿這個寶物
如過沒有被包含,你只能不拿這個寶物
\[dp[i][S]+=dp[i+1][S]*1/m\]
程式碼
#include<iostream> #include<cstdio> #include<cstring> #define re register #define max(a,b) ((a)>(b)?(a):(b)) inline int read() { char c=getchar(); int x=0,r=1; while(c<'0'||c>'9') { if(c=='-') r=-1; c=getchar(); } while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar(); return x*r; } double dp[102][32769]; int n,m,N; int cost[16]; int f[16]; int main() { n=read(),m=read(); for(re int i=1;i<=m;i++) { cost[i]=read(); int x=read(),y=0; while(x) y|=1<<(x-1),x=read(); f[i]=y; } N=(1<<m)-1; for(re int i=0;i<=N;i++) dp[n+1][i]=0; for(re int i=n;i;i--) for(re int j=0;j<=N;j++) { for(re int k=1;k<=m;k++) if(((f[k]|j)==j)) { dp[i][j]+=max(dp[i+1][j],dp[i+1][j|(1<<(k-1))]+cost[k])/double(m); }else dp[i][j]+=dp[i+1][j]/double(m); } printf("%.6lf",dp[1][0]); return 0; }