比較噁心的機率(指望)+狀壓DP,想正推2H的我瑟瑟發抖git
因爲數據範圍不大,所以咱們能夠直接狀壓每一個寶物取或不取的狀況,設\(f_{i,j}\)表示前\(i\)輪且寶物是否取過的狀態爲\(j\)時的方案總數,可是咱們發現這樣可能會致使一些不合法的狀態也獲得轉移,所以咱們考慮倒推spa
用\(f_{i,j}\)表示表示在第\(1\)輪到第\(i-1\)輪內寶物是否取過的狀態爲\(j\),第\(i\)輪到第\(k\)輪的最大指望得分,那麼這樣就能夠經過倒推動行轉移了。code
具體轉移的時候咱們枚舉全部的寶物限制,那麼轉移就很明顯了it
不過因爲這裏要求的是指望值,而每一次須要除以\(n\),最後的\(f_{1,0}\)即爲答案io
CODEclass
#include<cstdio> #include<cctype> using namespace std; typedef double DB; const int N=16,INF=-1e9; int n,p[N],m,s[N],x,tot; DB f[105][(1<<N)+5]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; int flag=1; while (!isdigit(ch=tc())) flag=ch^'-'?1:-1; while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); x*=flag; } inline int calc(int x) { int res=0; while (x) res+=x&1,x>>=1; return res; } inline DB max(DB a,DB b) { return a>b?a:b; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i,j,k; read(m); read(n); tot=(1<<n)-1; for (i=0;i<n;++i) { read(p[i]); read(x); while (x) s[i]|=(1<<x-1),read(x); } for (i=m;i>=1;--i) for (j=0;j<=tot;++j) { for (k=0;k<n;++k) if ((s[k]&j)==s[k]) f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<k)]+p[k]); else f[i][j]+=f[i+1][j]; f[i][j]=(DB)f[i][j]/n; } return printf("%.6lf",f[1][0]),0; }