【SHOI2002】百事世界杯之旅

....在2002年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字。 只要凑齐所有百事球星
的名字,就可参加百事世界杯之旅的抽奖活动,获得球星背包,随声听,更克赴日韩观看世界杯。还不赶
快行动!"
你关上电视,心想:假设有n个不同的球星名字,每个名字出现的概率相同,平均需要买几瓶饮料才能凑齐
所有的名字呢?

2002年上海省选的水题

对于任何一个时候,假设已经收集了 (i) 种球星名字
那么再买一瓶饮料,收集到不同名字的概率 (f(i)=dfrac{n-i}{n})

所以收集到所有名字的概率就是 (sum_{i=1}^{n}dfrac{n}{i})

感觉本题的难点在于输出答案

如果说让你输出期望值(小数)的话,就是真的大水题了
然而题目让你使用一种恶心的方法输出带分数!

所以把分数求出来后,要算出整数部分(g),分子部分(fz)和分母部分(fm)
先输出(len(g))个空格,然后输出(fz)(为0则不输出)
第二行输出整数(g),输出(len(fm))个下划线
第三行输出(len(g))个空格,再输出分母(fm)……
而且还要特判是否有分数部分
反正是很恶心的输出方式啦

代码:

#include<bits/stdc++.h>
#define ll long long
#define fm ans.m
#define fz ans.z
using namespace std;

int n;
struct Fs
{
	ll m,z;
}ans;

int cal(ll x)
{
	int res=0;
	while(x)
	{
		x/=10;
		res++;
	}
	return res;
}

ll gcd(ll a,ll b) {return b? gcd(b,a%b):a;}
ll g;

int main()
{
	fm=1;
	scanf("%d",&n);
	for(register int i=1;i<=n;++i)
	{
		fz=fz*i+fm*n;
		fm*=i;
		g=gcd(fz,fm);
		fz/=g;
		fm/=g;
	}
	g=fz/fm;
	fz%=fm;
	if(!fz)
	{
		printf("%lld
",g);
		return 0;
	}
	for(register int i=1;i<=cal(g);++i) putchar(' ');
	printf("%lld
",fz);
	if(g) printf("%lld",g);
	for(register int i=1;i<=cal(fm);++i) putchar('-');puts("");
	for(register int i=1;i<=cal(g);++i) putchar(' ');
	printf("%lld
",fm);
	return 0;
}
原文地址:https://www.cnblogs.com/tqr06/p/11628460.html