【SHOI 2002】百事世界杯之旅

【题目】

传送门

题目描述:

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

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

输入格式:

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

输出格式:

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

分数必须是不可约的。

样例数据:

输入
2

输出
3


【分析】

话说这道题输出好迷啊

首先要有一个结论:假设现在已经收集了 k k 个球星的名字,那么要使球星的名字达到 k + 1 k+1 ,平均需要买 n n k \frac{n}{n-k} 瓶饮料

感性理解一下吧(反正我也不会证),现在已经有 k k 个球星的名字,下一次买饮料买到新的球星名字的概率就是 n k n \frac{n-k}{n} ,那平均买 n n k \frac{n}{n-k} 次就可以买到新的了

那么答案就很好算了,就是 n 1 + n 2 + . . . + n n \frac{n}{1}+\frac{n}{2}+...+\frac{n}{n} (提一个 n n 就是调和级数了)

由于数据规模并不大,所以直接开 l o n g long l o n g long 进行计算就可以了,还要注意边求和边约分

再次吐槽一下输出,太鬼畜了。。。


【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long lcm(long long x,long long y)  {return x*y/__gcd(x,y);}
void calc(long long &mol,long long &den,long long x,long long y)
{
	long long l=lcm(den,y);
	mol*=l/den,x*=l/y;mol+=x,den=l;
	long long g=__gcd(mol,den);
	mol/=g,den/=g;
}
int len(long long x)
{
	int ans=0;
	while(x!=0)  ans++,x/=10;
	return ans;
}
int main()
{
	int n,i;
	scanf("%d",&n);
	long long mol=n,den=1;
	for(i=2;i<=n;++i)
	  calc(mol,den,n,i);
	if(mol%den==0)  printf("%lld",mol);
	else
	{
		int num1=len(den);
		int num2=len(mol/den);
		for(i=1;i<=num2;++i)  printf(" ");
		printf("%lld\n%lld",mol%den,mol/den);
		for(i=1;i<=num1;++i)  printf("-");
		printf("\n");
		for(i=1;i<=num2;++i)  printf(" ");
		printf("%lld",den);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/83151822