P4450 收集邮票

链接:

P4450


题意:

\(n\) 种不同的邮票,每次随机购买其中一种,即购买每种邮票的概率是 \(\dfrac 1n\),第 \(i\) 次购买的价格是 \(i\) 元,求买得所有种类邮票的期望价格。


分析:

想到一点,平方的期望不是期望的平方,这也能适用在这道题上,也就是说这道题不能直接用期望次数来算。

然后做法很很神仙,是期望概率dp,做过百事世界杯之旅可能会发现两道题很像,我们可以容易地算出期望次数。设 \(f[i]\) 表示已经买到了 \(i\) 种后还需要买的期望次数,接下来有 \(\dfrac in\) 的概率买到已经有的,有 \(\dfrac{n-i}n\) 的概率买到新的,那么 \(f[i]=\dfrac in(f[i]+1)+\dfrac{n-i}n(f[i+1]+1)\),整理可得 \(f[i]=f[i+1]+\dfrac n{n-i}\),显然 \(f[n]=0\)

考虑设 \(g[i]\) 表示已经买到了 \(i\) 种后还需要的期望价格,接下来有 \(\dfrac in\) 的概率买到已经有的,有 \(\dfrac{n-i}n\) 的概率买到新的,这里用到一个设计dp时费用提前的trick,也就是说,现在买一次会给以后每次购买加 1 的价格,我们把这个价格提前到这次购买的转移中,状态转移方程就是:

\[g[i]=\frac in(g[i]+f[i]+1)+\dfrac{n-i}n(g[i+1]+f[i+1]+1) \]

其中的 \(f\) 就是费用提前了,然后后面的 \(+1\) 是这一次的贡献。

整理过后就是

\[g[i]=g[i+1]+f[i+1]+\frac i{n-i}f[i]+\frac n{n-i} \]

于是只需要同时维护 \(f\)\(g\) 就好了。


算法:

同时维护 \(f\)\(g\),按期望dp方程转移即可 \(O(n)\) 解决。


代码:
#include<bits/stdc++.h>
using namespace std;
int n;
double f[10005],g[10005];
signed main(){
	cin>>n;
	f[n]=g[n]=0;
	for(int i=n-1;i>=0;i--)
		f[i]=f[i+1]+double(n)/(n-i),
		g[i]=g[i+1]+f[i+1]+double(i)/(n-i)*f[i]+double(n)/(n-i);
	cout<<fixed<<setprecision(2)<<g[0];
	return 0;
}

题外话:

神仙期望dp题/se

posted @ 2021-11-07 18:35  llmmkk  阅读(113)  评论(0编辑  收藏  举报