hdu4336 Card Collector 【最值反演】

题目链接

hdu4336

题解

最值反演

也叫做(min-max)容斥,在计算期望时有奇效

[max{S} = sumlimits_{T in S} (-1)^{|T| + 1}min{T} ]

证明:
(S = {a_i}),其中对于(i < j)(a_i < a_j)
那么我们计算每一个(a_i)的贡献,有

[egin{aligned} sumlimits_{T in S} (-1)^{|T| + 1}min{T} &= sumlimits_{i = 1}^{n}a_isumlimits_{j = 0}^{n - i}(-1)^{j}{n - i choose j}\ &= sumlimits_{i = 1}^{n}a_i[n - i = 0]\ &= sumlimits_{i = 1}^{n}a_i[n = i]\ &= a_n\ &= max{S} end{aligned} ]

证毕

对于此题,我们想要求出所有卡片集合(S)中最晚出现的卡片的期望,就转化为计算(S)的所有子集中最早出现的期望
对于一个集合(T),显然出现一张卡片的期望为

[frac{1}{sumlimits_{i in T}p_i} ]

枚举子集计算即可
复杂度(O(2^n))

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 25,maxm = 100005,INF = 1000000000;
double p[maxn],ans;
int n;
int main(){
	while (~scanf("%d",&n)){
		REP(i,n) scanf("%lf",&p[i]);
		int maxv = (1 << n) - 1; ans = 0;
		for (int s = 1; s <= maxv; s++){
			int cnt = 0; double tmp = 0;
			for (int e = s,j = 1; e; e >>= 1,j++)
				if (e & 1) cnt++,tmp += p[j];
			ans += (cnt & 1) ? 1 / tmp : -1 / tmp;
		}
		printf("%.8lf
",ans);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/9230174.html