​收集邮票​

老套路了,从后往前递推

但是这题有一个特殊的地方

每次邮票的价格不是邮票的固有属性,而是依赖于当前取的次数

所以想到需要维护一个 f [ i ] f[i] f[i]表示取完 i i i种情况下,完成任务的期望次数

那么本次有 i n \frac{i}{n} ni的机会摸到已有的邮票, n − i n \frac{n-i}{n} nn−i的概率摸到未有的邮票

f [ i ] = f [ i ] ∗ i n + f [ i + 1 ] ∗ n − i n + 1 f[i]=f[i]*\frac{i}{n}+f[i+1]*\frac{n-i}{n}+1 f[i]=f[i]∗ni+f[i+1]∗nn−i+1

维护 g [ i ] g[i] g[i]表示取完 i i i种情况下,完成任务的的期望价格

g [ i ] = i n ∗ ( g [ i ] + f [ i ] + 1 ) + n − i n ∗ ( g [ i + 1 ] + f [ i + 1 ] + 1 ) g[i]=\frac{i}{n}*(g[i]+f[i]+1)+\frac{n-i}{n}*(g[i+1]+f[i+1]+1) g[i]=ni∗(g[i]+f[i]+1)+nn−i∗(g[i+1]+f[i+1]+1)

其实这里用到了费用提前的思想

我 们 从 后 往 前 递 推 , 每 次 递 推 的 时 候 花 费 f [ i ] + 1 或 f [ i + 1 ] + 1 我们从后往前递推,每次递推的时候花费f[i]+1或f[i+1]+1 我们从后往前递推,每次递推的时候花费f[i]+1或f[i+1]+1

这 样 推 到 g [ 0 ] 的 时 候 , 就 是 正 确 的 这样推到g[0]的时候,就是正确的 这样推到g[0]的时候,就是正确的

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n,m;
double x[maxn],f[maxn];
int main()
{
cin >> n;
x[n]=f[n]=0;
for(int i=n-1;i>=0;i--)//获得i张的期望消耗
{
double p=i*1.0/n;
x[i]=( 1-p )*( x[i+1]+1 )+p;
x[i]/=(1-p);
f[i]=( 1-p )*( f[i+1]+x[i+1]+1 )+p*( x[i]+1 );
f[i]/=(1-p);
}
printf("%.2lf",f[0] );
}