题目链接:戳我

看到期望,想着不要从前转移。

一次后能买到不同种类的概率为\(\frac{n-i}{n}\)
两次后能买到不同种类的概率为\(\frac{i}{n}\times \frac{n-i}{n}\)
n次后能买到不同种类的概率为\((\frac{i}{n})^n\times \frac{n-i}{n}\)

设总期望为\(E=\frac{n-i}{n}\times1+\frac{i}{n}\times \frac{n-i}{n}\times 2+(\frac{i}{n})^2\times \frac{n-i}{n}\times 3+...+(\frac{i}{n})^{\infty}\times \frac{n-i}{n}\times{\infty}\)

\(\frac{i}{n}E=\frac{i}{n}\times \frac{n-i}{n}\times 1+(\frac{i}{n})^2\times \frac{n-i}{n}\times 2+...+(\frac{i}{n})^{\infty}\times \frac{n-i}{n}\times {\infty}\)

\(E=(\frac{i}{n})^0+(\frac{i}{n})^1+(\frac{i}{n})^2+....(1)\)

\(\frac{i}{n}E=(\frac{i}{n})^1+(\frac{i}{n})^2+....(2)\)

\((1)-(2)\;\; E=\frac{n}{n-i}\)

我们考虑\(f[i]\)表示已经买到了i个名字的期望次数

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

然后就可以递推了。

输出比较神奇,但是注意一点也不会出错的。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define MAXN 40
#define ll long long
using namespace std;
int n;
long long fv[MAXN],fn[MAXN];
inline ll gcd(ll x,ll y)
{
    if(!y) return x;
    else return gcd(y,x%y);
}
inline int solve(ll x)
{
    int cur_ans=0;
    while(x)
    {
        cur_ans++;
        x/=10;
    }
    return cur_ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&n);
    fv[1]=1,fn[1]=1;
    for(int i=1;i<n;i++)
    {
        fv[i+1]=fv[i]*(n-i)+fn[i]*n;
        fn[i+1]=fn[i]*(n-i);
        long long cur=gcd(fn[i+1],fv[i+1]);
        fn[i+1]/=cur,fv[i+1]/=cur;
    }
    ll cur=fv[n]/fn[n];
    if(fv[n]%fn[n]==0) cout<<cur<<endl;
    else
    {
        fv[n]-=cur*fn[n];
        int len1=solve(cur);
        for(int i=1;i<=len1;i++) printf(" ");
        printf("%lld\n",fv[n]);
        int len2=solve(max(fv[n],fn[n]));
        printf("%lld",cur);
        for(int i=1;i<=len2;i++) printf("-"); puts("");
        for(int i=1;i<=len1;i++) printf(" ");
        printf("%lld\n",fn[n]);
    }
    return 0;
}