洛咕

题意:有\(n(n<=100000)\)种不同的邮票,皮皮想收集所有种类的邮票.唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为1/n.但是由于凡凡也很喜欢邮票,所以皮皮购买第k张邮票需要支付k元钱.现在皮皮手中没有邮票,皮皮想知道自己得到所有种类的邮票需要花费的钱数目的期望.

分析:首先第一步转换一下题目,发现只要知道了要买多少次就可以计算出花了多少钱,所以本题是求期望次数.设期望次数为x,则\(ans=x*(x+1)/2=(x+x^2)/2.\)

刚开始想的是,设\(g[i]\)表示获得i种邮票的期望次数,\(f[i]\)表示获得i种邮票的期望次数的平方.那么答案就是\(\frac{g[n]+f[n]}{2},\)然后递推式是\(g[i]=(g[i-1]+1)*\frac{n-i}{n}+(g[i]+1)*\frac{i}{n}\)(前者表示第i次买到了新种类邮票,后者表示第i次买到了已经买到过的邮票),移项化简可以得到\(g[i]=g[i-1]+\frac{n}{n-i}\).同理\(f[i]=(f[i-1]+2*g[i-1]+1)*\frac{n-i}{n}+(f[i]+2*a[i]+1)*\frac{i}{n}\)(联系一下完全平方式的展开就能得到了),然后同样移项化简可以得到\(f[i]=f[i-1]+2*g[i-1]+1+(2*g[i]+1)*\frac{i}{n-i}\).

然后写着写着发现因为要除以\(n-i\),所以会出现除以0的情况,于是就炸了.

然后想着顺着推不行,那就倒着推吧.\(g[i]\)表示获得i种邮票后还需要的期望次数,\(f[i]\)表示获得i种邮票后还需要的期望次数的平方.推一下可以发现,式子大体相同就是\(i-1\)都变了\(i+1\),所以我们初始化\(g[n]=f[n]=0\),然后倒着推出\(g[0],f[0]\)即可.最终答案就是\((g[0]+f[0])/2.\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=10005;
double g[N],f[N];
int main(){
    int n=read();
    /*for(int i=1;i<=n;++i){
        g[i]=g[i-1]+1.0*n/(n-i);
        f[i]=f[i-1]+2*g[i-1]+1+1.0*i*(2*g[i]+1)/(n-i);
    }
    printf("%.2lf\n",(f[n]+g[n])/2.0);*/
    for(int i=n-1;i>=0;--i){
        g[i]=g[i+1]+1.0*n/(n-i);
        f[i]=f[i+1]+2*g[i+1]+1+1.0*i*(2*g[i]+1)/(n-i);
    }
    printf("%.2lf\n",(g[0]+f[0])/2.0);
    return 0;
}
02-12 01:45