[JZOJ4685] 【NOIP2016提高A组8.12】礼物
第一问是显然的, 把所有的权值加起来。
看着数据范围就知道是状压DP。
所以设$\large f[S]$为已买状态为S的期望步数。
那么$\large f[S] = \sum f[S']*p[i] + (1 - \sum p[i])*f[S]+1 $,因为有$\large p[i]$的几率选到没选过的某一个, 有$\large 1- \sum p[i]$的几率选择之前选过的或者没有选到。
然后移项 $\large f[S]=\frac{\sum p[i]*f[S']+1}{\sum p[i]}$.
于是可以递推了。
复杂度$\large O(2^{N})$
#include <iostream> #include <cstdio> using namespace std; inline int read() { int res=0;char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=getchar(); return res; } #define ll long long #define reg register int n; double p[25]; int w[25]; ll ans; int bin[25]; double f[1<<22]; int main() { bin[0] = 1;for (int i = 1 ; i <= 22 ; i ++) bin[i] = bin[i-1] << 1; n = read(); for (reg int i = 1 ; i <= n ; i ++) scanf("%lf", &p[i]), ans += (w[i] = read()); printf("%lld\n", ans); for (reg int S = 1 ; S <= (1 << n) - 1 ; S ++) { double tot = 0; for (reg int i = 1 ; i <= n ; i ++) { if (S & bin[i-1]) f[S] += f[S-bin[i-1]] * p[i], tot += p[i]; } f[S] = (f[S] + 1) / tot; } printf("%.3lf\n", f[(1<<n)-1]); return 0; }