逆推期望DP。设f[i][j]为1~i-1中吃到的宝物集合为j,在i~k轮能得到的最大期望分数。
如果不吃显然f[i][j]+=f[i+1][j]/n
如果吃就是f[i][j]+=max(f[i+1][j]/n,(f[i+1][j|(1<<k-1)]+q[k])/n)
然后照着这样的方程式搞一搞,最后答案就是f[1][0]。
话说我一开始的状态设计就是题解吐槽的那种,然后我想了一个多小时发现:诶?转移不动呀?
qwq
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> #include<cstdlib> #define maxk 110 #define maxn 16 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch==‘-‘) f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-‘0‘; ch=getchar(); } return num*f; } double f[maxk][1<<maxn]; int need[maxk][maxk],tot[maxk]; int q[maxk]; double ans; int cnt; int main(){ int m=read(),n=read(); for(int i=1;i<=n;++i){ q[i]=read(); int x=read(); while(x){ need[i][++tot[i]]=x; x=read(); } } for(int i=m;i>0;--i) for(int j=0;j<(1<<n);++j){ for(int k=1;k<=n;++k){ int o=1<<(k-1); bool flag=0; for(int l=1;l<=tot[k];++l) if(!(j&(1<<(need[k][l]-1)))){ flag=1; break; } if(flag) f[i][j]+=f[i+1][j]; else f[i][j]+=max(f[i+1][j],f[i+1][j|o]+q[k]); } f[i][j]/=(double)n; } printf("%.6lf",f[1][0]); return 0; }