#1468 百事世界杯之旅
题面
“……在2002年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字。只要凑齐所有百事球星的名字,就可参加百事世界杯之旅的抽奖活动,获得球星背包,随声听,更克赴日韩观看世界杯。还不赶快行动!”
你关上电视,心想:假设有n个不同的球星名字,每个名字出现的概率相同,平均需要买几瓶饮料才能凑齐所有的名字呢?
输入
整数n(2≤n≤33),表示不同球星名字的个数。
输出
如果输出是整数,那么直接输出一个整数
如果有分数,分数必须不可再约。 分3行打印 第一行是分子,前面有整数部分的位数+1个空格
第二行是整数部分+1个空格+分母位数个、‘-’
第三行是分母,前面有整数部分的位数+1个空格
样例输入
2
样例输出
3
SOL
我们假设当前已经有k个球星,那么我们要开出第k+1个球星的期望为n/n-k,于是开出n个球星的期望为
n∗∑i=1n1/in*\sum_{i=1}^{n}1/in∗i=1∑n1/i
于是这道题最难的就是输出带分数(还要最简,丧心病狂!!!)……
经过思考,可以考虑维护每个值的整数部分,分数部分通分加起来,分数部分的和的整数部分加到当前统计的整数部分里。
完了。
代码太丑,望诸位神仙见谅!
代码:
#include<bits/stdc++.h>
#define int long long
#define N 100005
using namespace std;
inline int rd(){
static char ch=0;int register data=0,w=1;
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(isdigit(ch))data=(data<<1)+(data<<3)+ch-'0',ch=getchar();
return data*w;
}
int z,n,a,b=1;//z+(a/b)
inline int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}
signed main(){
n=rd();
for(int register i=1;i<=n;i++)z+=n/i,b*=i/gcd(b,i);
for(int register i=1;i<=n;i++)a+=n*b/i%b;
int register num=0,x=gcd(a,b);
a/=x,b/=x;
z+=a/b;a%=b;
if(!a){cout<<z;exit(0);}
x=z;while(x){x/=10;num++;}if(num)num++;
while(num--)putchar(' ');cout<<a<<endl;
if(z)cout<<z;putchar(' ');
num=0;x=b;while(x){x/=10;num++;}while(num--)putchar('-');cout<<endl;
num=0;x=z;while(x){x/=10;num++;}if(num)num++;
while(num--)putchar(' ');cout<<b;
}