1. 程式人生 > >bzoj 1076: [SCOI2008]獎勵關

bzoj 1076: [SCOI2008]獎勵關

目前 sin 最大 ios 有一個 決定 cpp 正在 gpo

Description

你正在玩你最喜歡的電子遊戲,並且剛剛進入一個獎勵關。在這個獎勵關裏,系統將依次隨機拋出k次寶物,每次你都可以選擇吃或者不吃(必須在拋出下一個寶物之前做出選擇,且現在決定不吃的寶物以後也不能再吃)。
寶物一共有n種,系統每次拋出這n種寶物的概率都相同且相互獨立。也就是說,即使前k-1 次系統都拋出寶物1(這種情況是有可能出現的,盡管概率非常小),第k次拋出各個寶物的概率依然均為1/n。
獲取第 i 種寶物將得到Pi分,但並不是每種寶物都是可以隨意獲取的。第i種寶物有一個前提寶物集合Si。只有當Si中所有寶物都至少吃過一次,才能吃第i 種寶物(如果系統拋出了一個目前不能吃的寶物,相當於白白的損失了一次機會)。註意,Pi 可以是負數,但如果它是很多高分寶物的前提,損失短期利益而吃掉這個負分寶物將獲得更大的長期利益。

假設你采取最優策略,平均情況你一共能在獎勵關得到多少分值?

Solution

期望DP,註意到\(n\)很小,可以狀壓
\(dp[i][j]\) 為走到 \(i\) 這個節點當前的狀態為 \(j\) 的最大期望分值
\(dp[i][S]+=max(dp[i+1][S],1.0*(a[j]+dp[i+1][S|(1<<(j-1))]))/n\),該狀態包含該寶物的前提.
\(dp[i][S]+=dp[i+1][S]/n\),該寶物的前提沒有被包含
註意期望DP倒推.

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring> #include <cstdio> #include <cmath> #define RG register #define il inline #define iter iterator #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; const int N=105; double dp[N][1<<15];int a[N],c[N]; void
work() { int K,n,x; scanf("%d%d",&K,&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); scanf("%d",&x); while(x)c[i]|=(1<<(x-1)),scanf("%d",&x); } int lim=1<<n; for(int i=K;i>=1;i--){ for(int S=0;S<lim;S++){ for(int j=1;j<=n;j++){ int T=c[j]; if((S&T)==T) dp[i][S]+= max(dp[i+1][S],1.0*(a[j]+dp[i+1][S|(1<<(j-1))]))/n; else dp[i][S]+=dp[i+1][S]/n; } } } printf("%.6lf\n",dp[1][0]); } int main() { work(); return 0; }

bzoj 1076: [SCOI2008]獎勵關