题目分析
期望的通常套路是逆推。
设 f ( i ) f(i) f(i)表示当前手头已经有 i i i种邮票的情况下,收集满邮票期望要买多少次。那么 f ( i ) = i n f ( i ) + n − i n f ( i + 1 ) + 1 f(i)=\frac{i}{n} f(i)+\frac{n-i}{n} f(i+1)+1 f(i)=nif(i)+nn−if(i+1)+1,即 f ( i ) = f ( i + 1 ) + n n − i f(i)=f(i+1)+\frac{n}{n-i} f(i)=f(i+1)+n−in
设 g ( i ) g(i) g(i)表示当前手头已经有 i i i种邮票的情况下,买的第一张价格为 1 1 1,第二张价格为 2 2 2,以此类推,期望要花多少钱。那么我做完“买邮票”这个操作后,到达的新状态下,继续决策买的邮票的价格都会加1,算总共加的期望,可以得到式子:
g ( i ) = i n ( g ( i ) + f ( i ) ) + n − i n ( g ( i + 1 ) + f ( i + 1 ) ) + 1 g(i)=\frac{i}{n} (g(i)+f(i)) + \frac{n-i}{n} (g(i+1)+f(i+1))+1 g(i)=ni(g(i)+f(i))+nn−i(g(i+1)+f(i+1))+1
即:
g ( i ) = i n − i f ( i ) + g ( i + 1 ) + f ( i + 1 ) + n n − i g(i)=\frac{i}{n-i} f(i)+g(i+1)+f(i+1)+\frac{n}{n-i} g(i)=n−iif(i)+g(i+1)+f(i+1)+n−in
代码
#include<bits/stdc++.h>
using namespace std;
#define RI register int
typedef double db;
const int N=10005;
int n;db f[N],g[N];
int main()
{
scanf("%d",&n);
for(RI i=n-1;i>=0;--i) f[i]=f[i+1]+(db)n/(db)(n-i);
for(RI i=n-1;i>=0;--i)
g[i]=g[i+1]+f[i+1]+(db)i/(db)(n-i)*f[i]+(db)n/(db)(n-i);
printf("%.2lf\n",g[0]);
return 0;
}