【题解】LuoGu2473:奖励关

原题传送门
d p i , j dp_{i,j} dpi,j表示到第 i i i轮, 1 1 1~ i − 1 i-1 i1轮取得奖励集合为 j j j的答案
顺推的话会推出一些不合理的结果,所以采用逆推
对于枚举一个 k k k号奖励,如果当前满足前置条件
d p i , j + = m a x ( d p i + 1 , j , d p i + 1 , j ∣ = ( 1 < < k − 1 ) + p k ) dp_{i,j}+=max(dp_{i+1,j},dp_{i+1,j|=(1<dpi,j+=max(dpi+1,j,dpi+1,j=(1<<k1)+pk)
否则 d p i , j + = d p i + 1 , j dp_{i,j}+=dp_{i+1,j} dpi,j+=dpi+1,j
等概率,最终 d p i , j / = n dp_{i,j}/=n dpi,j/=n

Code:

#include 
#define maxn 110
#define maxm 100010
using namespace std;
double dp[maxn][maxm];
int n, m, power[maxn], a[maxn], p[maxn];

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

int main(){
	m = read(), n = read();
	power[0] = 1;
	for (int i = 1; i <= n; ++i) power[i] = power[i - 1] << 1;
	for (int i = 1; i <= n; ++i){
		p[i] = read();
		int x = read();
		while (x) a[i] |= power[x - 1], x = read();
	}
	for (int i = m; i; --i)
		for (int j = 0; j < power[n]; ++j){
			for (int k = 1; k <= n; ++k)
				if ((j & a[k]) == a[k]) dp[i][j] += max(dp[i + 1][j], dp[i + 1][j | power[k - 1]] + p[k]);
				else dp[i][j] += dp[i + 1][j];
			dp[i][j] /= n;
		}
	printf("%.6lf\n", dp[1][0]);
	return 0;
}

你可能感兴趣的:(题解,LuoGu,DP,题解,LuoGu,dp,状压)