Evanyou Blog 彩带

  题目传送门

百事世界杯之旅

题目描述

“……在2002年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字。只要凑齐所有百事球星的名字,就可参加百事世界杯之旅的抽奖活动,获得球星背包,随声听,更克赴日韩观看世界杯。还不赶快行动!”

你关上电视,心想:假设有n个不同的球星名字,每个名字出现的概率相同,平均需要买几瓶饮料才能凑齐所有的名字呢?

输入输出格式

输入格式:

 

整数n(2≤n≤33),表示不同球星名字的个数。

 

输出格式:

 

输出凑齐所有的名字平均需要买的饮料瓶数。如果是一个整数,则直接输出,否则应该直接按照分数格式输出,例如五又二十分之三应该输出为(复制到记事本):$5 frac{3}{20}$第一行是分数部分的分子,第二行首先是整数部分,然后是由减号组成的分数线,第三行是分母。减号的个数应等于分母的为数。分子和分母的首位都与第一个减号对齐。

分数必须是不可约的。

 

输入输出样例

输入样例#1: 
2
输出样例#1: 
3

 


  分析:

  很明显的数学期望。

  首先我们设当前还需要收集$k$个球星,现在的装态为$f(n,k)$,那么转移的方程就是:$f(n,k)=frac {(n-k)*f(n,k)}{n}+frac {k*f(n,k-1)}{n}+1$,因为很明显我们收集到了$n-k$个球星,那么抽到没收集到的球星的概率为$frac {k}{n}$,抽到收集到的球星的概率为$frac {n-k}{n}$,后面的那个+1就是代表多买了一瓶饮料。然后把方程移项,得到:$f(n,k)=f(n,k-1)+frac {n}{k}$。然后注意输出就行了。

  Code:

//It is made by HolseLee on 25th July 2018
//Luogu.org P1291
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
ll n,ans,m=1,ka;

inline ll gcd(ll x,ll y)
{
    return y==0?x:gcd(y,x%y);
}

inline ll get(ll x)
{
    ll ret=0;
    while(x){
        ret++;x/=10;
    }
    return ret;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=n;i>=1;i--){
        ans=ans*i+m*n;
        m*=i;ka=gcd(ans,m);
        ans/=ka;m/=ka;
    }
    ka=ans/m;
    ans%=m;
    if(ans==0)
        printf("%lld
",ka);
    else {
        ll gi=get(ka),lu=get(m);
        for(int i=1;i<=gi;i++)
            printf(" ");
        printf("%lld
",ans);
        if(ka>0)
            printf("%lld",ka);
        for(int i=1;i<=lu;i++)
            printf("-");
        printf("
");
        for(int i=1;i<=gi;i++)
            printf(" ");
        printf("%lld
",m);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cytus/p/9368419.html