【题目描述】
输入两个正整数,输出,保留5位小数。输入包含多组数据,结束标记为n=m=0。提示:本题有陷阱。
【样例输入】
2 4
65536 655360
0 0
【样例输出】
Case 1: 0.42361
Case 2: 0.00001
【题目来源】
刘汝佳《算法竞赛入门经典 第2版》习题2-4 子序列的和(subsequence)
【解析】
#include<stdio.h>
int main(){
int n, m, kase=0;
while(scanf("%d%d", &n, &m)==2 && 0!=n && 0!=m){
double sum = 0;
for(int i=n; i<=m; i++){
sum += 1.0/i/i;
}
printf("Case %d: %.5f\n", ++kase, sum);
}
return 0;
}
本题的陷阱有三个:
(1)数据类型转换:输入的n、m为整数,而输出的结果为小数,需要转换数据类型,所以sum += 1.0/i/i中的1.0不能写成1。
(2)输出格式问题:输出格式要与样例严格一致,如Case和数字之间、冒号与输出值之间有且只有一个空格。为避免出错,最好将样例直接复制到代码中。
(3)数据超限问题:估计这就是题中所指的陷阱。因为题目所给数据范围为,而int型的最大值约为,因此代码如果写成sum += 1.0/(i*i),大数相乘就会导致数据超限。当然,这个问题也可以通过将int型改为long long型解决。
此外,上面的代码有两处写得不够简明:
(1)变量不为0的判断,代码中用0!=n的形式不够简明,它其实等价于n。
(2)从n到m的遍历不用引入第3个变量,直接用n自加即可。
优化后的代码:
#include<stdio.h>
int main(){
int n, m, kase=0;
while(scanf("%d%d", &n, &m)==2 && n && m){
double sum = 0;
for(;n<=m; n++){
sum += 1.0/n/n;
}
printf("Case %d: %.5f\n", ++kase, sum);
}
return 0;
}