[SCOI2008]奖励关

XXXIV.[SCOI2008]奖励关

\(n\leq 15\)就是一眼状压。但这题难点不是状压,而是期望。

应该很容易就能想到,设\(f[i][j]\)表示前\(i\)次操作后,状态为\(j\)的期望收益。但这有个问题——我们不知道如果刷到一个负数收益应不应该选,因为我们不知道这个负数收益在后面会带给我们怎样的期望收益。

因为必须要直到后面的内容,所以考虑倒序DP:设\(f[i][j]\)表示前\(i\)次操作后状态为\(j\),在后\(K-i\)次操作中的期望收益。这样期望就可以直接取\(\max\)了——对后面的影响已经确定。

对于\(f[i][j]\),我们枚举一个\(k\),表示刷到第\(k\)个物品。如果\(k\)不可以选,有 f[i][j]+=f[i+1][j] ;否则,即\(k\)可以选,有f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<k)]+val[k])

这时期望就可以正常除以\(n\)了,因为刷到所有物品的概率是均等的。

复杂度\(O(k^22^n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,lim,val[16],sta[16];
double f[110][1<<16];
int main(){
	scanf("%d%d",&m,&n),lim=(1<<n);
	for(int i=0,x;i<n;i++){
		scanf("%d",&val[i]);
		scanf("%d",&x);
		while(x)sta[i]|=(1<<(x-1)),scanf("%d",&x);
	}
	for(int i=m;i;i--)for(int j=0;j<lim;j++){
		for(int k=0;k<n;k++)if((j&sta[k])==sta[k])f[i][j]+=max(f[i+1][j],f[i+1][j|(1<<k)]+val[k]);else f[i][j]+=f[i+1][j];
		f[i][j]/=n;
	}
	printf("%lf\n",f[1][0]);
	return 0;
}

posted @ 2021-03-30 15:45  Troverld  阅读(45)  评论(0编辑  收藏  举报