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 1⩽n⩽22, 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=1⋃X{li}=S的
X
X
X的期望值,其中
l
i
∈
S
,
∀
i
l_i\in S,\forall i
li∈S,∀i。
我们假设
∣
⋃
j
=
1
X
′
{
l
j
}
∣
=
i
,
\left|\bigcup_{j=1}^{X'}\{l_j\}\right|=i,
∣∣∣∣∣∣j=1⋃X′{lj}∣∣∣∣∣∣=i,则
P
(
∣
⋃
j
=
1
X
′
+
1
{
l
j
}
∣
=
i
+
1
)
=
n
−
i
n
=
p
i
.
P\left(\left|\bigcup_{j=1}^{X'+1}\{l_j\}\right|=i+1\right)=\frac{n-i}{n}=p_i.
P⎝⎛∣∣∣∣∣∣j=1⋃X′+1{lj}∣∣∣∣∣∣=i+1⎠⎞=nn−i=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=0∑n−1pi−1=ni=1∑ni1.
所以,本题只要求出倒数和数列的前
22
22
22项,再乘以项数即可。
此外本题还要求实现带分数的运算及输出。看了Discuss里其他人的代码,除开打表做的不谈基本都是直接在主程序中操作的。我个人其实更倾向于写一个带分数的类,虽然这样做势必会增加代码长度,但是主程序因此看起来简单了,同时也方便我debug。
第一次提交的时候TE了,后来发现,是因为分数部分约分的时候算法不太好,优化以后就可以AC了,时间和打表也差不多。