寒假也没啥事,不如刷刷题呗~
Uva10288
题意
麦片盒子里的优惠券编号从1到n,奖品(麦片)需要一套盒子,当然)。每个盒子一张优惠券,平均需要多少个盒子才能完成一套n张优惠券?
输入
一串正整数n(1<=n<=33),以EOF结束
输出
将平均要拿多少次才能集齐一套共n个的数学期望E以带分数的形式输出,若结果为整数,就只输出整数的部分。
思路
假设当前集了k种小卡片,那么获得新小卡片的概率为 (n-k)/n, 需要的步数期望为 n/(n-k)。 求和可得总的步数期望为:
E
=
n
/
n
+
n
/
(
n
−
1
)
+
…
+
n
/
1
=
n
∑
i
=
1
n
1
i
E = n/n + n/(n-1) + … + n/1 = n\sum_{i=1}^{n}\frac{1}{i}
E=n/n+n/(n−1)+…+n/1=ni=1∑ni1
主体框架:
- 三个数组保存1~33对应的整数部分、分子部分、分母部分。
- 开始的时候先算出这99个数。
- 一个while循环读入n,输出每次结果。
注意事项
- 及时约分
- 使用long long, int不够表示
样例输入
2
5
17
样例输出
3
5
11 –
12
340463
58 ------
720720
AC代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL lef[35],top[35],bottom[35];
LL n;
// E = n * (1/n + 1/(n-1) + … + 1/1)
inline LL _gcd_(LL fst, LL scd){
return (fst==0)?scd:_gcd_(scd%fst, fst);
}
void callculates() {
memset(lef, 0, sizeof(lef));
memset(top, 0, sizeof(top));
memset(bottom, 1, sizeof(bottom));
lef[1] = 1;top[1] = 0;bottom[1] = 1;
for (int i=2; i<34; i++) { //(1/n + 1/(n-1) + … + 1/1)
LL up = 1, down = 1,gcd;
for(int j=2; j<=i; j++) { //+1/j
up = up*j + down;
down = down * j;
gcd = _gcd_(up, down);
up /= gcd;
down /= gcd;
}
up *= i;
gcd = _gcd_(up, down);
up /= gcd;
down /= gcd;
lef[i] = up/down;
top[i] = up%down;
bottom[i] = down;
}
}
int main(){
//freopen("input.txt", "r", stdin);
callculates();
while(~scanf("%d", &n)) {
if (top[n] == 0) {printf("%d\n", lef[n]);}
else {
for(LL i = lef[n]; i>0; i/=10)printf(" ");printf(" %lld\n", top[n]);
printf("%lld ",lef[n]);
for(LL i = bottom[n]; i>0; i/=10)
printf("-");
printf("\n");
for(int i = lef[n]; i>0; i/=10)printf(" ");printf(" %lld\n", bottom[n]);
}
}
return 0;
}