HDU-1099 Lottery

Lottery

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/32768 K (Java/Others)

Problem Description

Eddy’s company publishes a kind of lottery.This set of lottery which are numbered 1 1 1 to n n n, and a set of one of each is required for a prize .With one number per lottery, how many lottery on average are required to make a complete set of n n n coupons?

Input

Input consists of a sequence of lines each containing a single positive integer n n n, 1 ⩽ n ⩽ 22 1\leqslant n\leqslant 22 1n22, giving the size of the set of coupons.

Output

For each input line, output the average number of lottery required to collect the complete set of n n n coupons. If the answer is an integer number, output the number. If the answer is not integer, then output the integer part of the answer followed by a space and then by the proper fraction in the format shown below. The fractional part should be irreducible. There should be no trailing spaces in any line of output.

Sample Input

2
5
17

Sample Output

3 
   5
11 --
   12
   340463
58 ------
   720720

Reference Code

#include<bits/stdc++.h>
using namespace std;
struct mfrac{
    int I,D,N;
    mfrac(int i,int d,int n){
        I=i,D=d,N=n;
    }
    mfrac reduction(){
        I+=D/N,D%=N;
        int g=__gcd(D,N);
        D/=g,N/=g;
        return *this;
    }
    mfrac operator+(const mfrac &oth)const{
        mfrac c(I+oth.I,D*oth.N+N*oth.D,N*oth.N);
        return c.reduction();
    }
    mfrac operator+=(const mfrac &oth){
        return *this=*this+oth;
    }
    mfrac operator*(const int &pro)const{
        mfrac c(I*pro,D*pro,N);
        return c.reduction();
    }
};
ostream& operator<<(ostream &out,const mfrac &f){
    if (f.D){
        char fI[20],fD[20],fN[20];
        sprintf(fI,"%d",f.I);
        sprintf(fD,"%d",f.D);
        sprintf(fN,"%d",f.N);
        for (int i=0;i<=strlen(fI);i++) out<<" ";
        for (int i=0;i<strlen(fD);i++) out<<fD[i];
        out<<"\n"<<f.I<<" ";
        for (int i=0;i<strlen(fN);i++) out<<"-";
        out<<"\n";
        for (int i=0;i<=strlen(fI);i++) out<<" ";
        for (int i=0;i<strlen(fN);i++) out<<fN[i];
    }
    else out<<f.I;
    return out;
}
int main(){
    int n;
    while (~scanf("%d",&n)){
        mfrac res(0,0,1);
        for (int i=1;i<=n;i++)
            res+=mfrac(0,1,i);
        cout<<res*n<<endl;
    }
    return 0;
}

Tips

本题因为是英文,题意理解起来似乎有些困难,这里不妨用数学语言解释一下:
已知有一集合 S S S满足 ∣ S ∣ = n \left|S\right|=n S=n,求满足 ⋃ i = 1 X { l i } = S \bigcup_{i=1}^{X}\{l_i\}=S i=1X{li}=S X X X的期望值,其中 l i ∈ S , ∀ i l_i\in S,\forall i liS,i

我们假设 ∣ ⋃ j = 1 X ′ { l j } ∣ = i , \left|\bigcup_{j=1}^{X&#x27;}\{l_j\}\right|=i, j=1X{lj}=i, P ( ∣ ⋃ j = 1 X ′ + 1 { l j } ∣ = i + 1 ) = n − i n = p i . P\left(\left|\bigcup_{j=1}^{X&#x27;+1}\{l_j\}\right|=i+1\right)=\frac{n-i}{n}=p_i. Pj=1X+1{lj}=i+1=nni=pi.因此, X = ∑ i = 0 n − 1 p i − 1 = n ∑ i = 1 n 1 i . X=\sum_{i=0}^{n-1}p_i^{-1}=n\sum_{i=1}^n\frac1i. X=i=0n1pi1=ni=1ni1.
所以,本题只要求出倒数和数列的前 22 22 22项,再乘以项数即可。

此外本题还要求实现带分数的运算及输出。看了Discuss里其他人的代码,除开打表做的不谈基本都是直接在主程序中操作的。我个人其实更倾向于写一个带分数的类,虽然这样做势必会增加代码长度,但是主程序因此看起来简单了,同时也方便我debug。
第一次提交的时候TE了,后来发现,是因为分数部分约分的时候算法不太好,优化以后就可以AC了,时间和打表也差不多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值