题目传送门

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

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

输入格式:

 

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

 


输出格式:

 

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

分数必须是不可约的。

 

输入样例#1: 

  1. 2
输出样例#1: 

  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:

 

  1. //It is made by HolseLee on 25th July 2018
  2. //Luogu.org P1291
  3. #include<bits/stdc++.h>
  4. using namespace std;
  5. typedef long long ll;
  6. ll n,ans,m=1,ka;
  7. inline ll gcd(ll x,ll y)
  8. {
  9. return y==0?x:gcd(y,x%y);
  10. }
  11. inline ll get(ll x)
  12. {
  13. ll ret=0;
  14. while(x){
  15. ret++;x/=10;
  16. }
  17. return ret;
  18. }
  19. int main()
  20. {
  21. ios::sync_with_stdio(false);
  22. cin>>n;
  23. for(int i=n;i>=1;i--){
  24. ans=ans*i+m*n;
  25. m*=i;ka=gcd(ans,m);
  26. ans/=ka;m/=ka;
  27. }
  28. ka=ans/m;
  29. ans%=m;
  30. if(ans==0)
  31. printf("%lld\n",ka);
  32. else {
  33. ll gi=get(ka),lu=get(m);
  34. for(int i=1;i<=gi;i++)
  35. printf(" ");
  36. printf("%lld\n",ans);
  37. if(ka>0)
  38. printf("%lld",ka);
  39. for(int i=1;i<=lu;i++)
  40. printf("-");
  41. printf("\n");
  42. for(int i=1;i<=gi;i++)
  43. printf(" ");
  44. printf("%lld\n",m);
  45. }
  46. return 0;
  47. }

 

 

 

版权声明:本文为cytus原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/cytus/p/9368419.html