目录
- 题目
- 解题思路
- 解题代码
- 1. 错误解法
- 2. 正确解法(1)
- 3. 正确解法(2)
- 4. 正确解法(3)
- 5. 正确解法(4)
题目
循环输入,每输入一个正整数n(n ≤ 65535), 输出1 + 2 + 3 + … + n 的值,并且多输出一个空行。当没有任何输入时,结束 程序。
解题思路
我们可以通过暴力枚举或者使用等差数列前n项和的公式来计算出来结果
解题代码
1. 错误解法
# include<stdio.h>
int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
int ans = n * (n + 1) / 2;
printf("%d\n",ans);
}
return 0;
}
这里为什么出错了呢?逻辑是正确的呀?😥
这里的n是小于等于65535的,当n是65535的时候,那么n * (n + 1)已经溢出了,因为65535 可以看作是(216-1),那么可以自行计算一下n * (n + 1)的值,会大于int 所能表示的最大值231-1,所以这种方法没有考虑到溢出,所以会出错。
2. 正确解法(1)
#include <stdio.h>
int main()
{
int n = 1;
while(scanf("%d",&n) != EOF)
{
int sum = 0;//(1)
while(n)
{
sum += n;
n--;
}
printf("%d\n",sum);
}
return 0;
}
- sum用于存放最后的相加得到的结果
3. 正确解法(2)
#include <stdio.h>
int main()
{
int n;
int sum = 0;
while(scanf("%d",&n) != EOF)
{
if (n % 2 == 0) //(1)
{
sum = n /2 * (n + 1);
}
else //(2)
{
sum = (n + 1) / 2 * n;
}
printf("%d\n",sum);
}
return 0;
}
- 如果输入的n是偶数的话,那么先计算等差数列求和公式中的n / 2,然后再乘(n + 1),这样将等差数列求和公式变一下形,那么我们就可以有效地避免错误解法中的n * (n + 1)这种溢出情况了。😎
- 如果输入的n是奇数的话,那么奇数加上一然后除以2,肯定得到的结果是偶数,那么我们也是将等差数列求和公式中的公式变一下形,从而有效地避免溢出。
总之,这里按照奇数和偶数分情况输出,是因为计算机中,计算除法是向下取整的,所以分奇偶情况来讨论的话,那么就不会因为计算机这种计算方法从而导致结果出错了。
4. 正确解法(3)
由于边界溢出问题,所以我们才会考虑这么多的。那么我们扩大一下存储结果的范围,那么就不用这么辛苦地考虑边界溢出问题了。
由于C语言中有无符号整型这种数据类型,它的存储范围是[0.232-1],这个题目中最大的范围是n * (n + 1),可以自己手动计算一下,n * (n + 1)的范围是小于无符号整型的最大表示范围的,所以我们可以使用无符号整型来存放结果而不用担心溢出。
#include <stdio.h>
int main()
{
int n;
while( scanf("%d",&n) != EOF )
{
unsigned int sum = 0;
sum += n * (n + 1) / 2;
printf("%u\n",sum);//(1)
}
return 0;
}
- 由于这里使用了无符号整型,那么注意输出的格式应该是%u
5. 正确解法(4)
我们可以考虑使用可以表示更大范围的数据类型来存储最后的结果,比如说这里使用 long long, long long 数据类型在C中可以表示的范围是: [- 263 , 263 -1],那么足以表示我们这道题目的结果了。
#include <stdio.h>
int main()
{
int n;
while( scanf("%d",&n) != EOF )
{
long long sum = 0;
sum = n * (n + 1) / 2;
printf("%lld\n",sum);//(1)
}
return 0;
}
- 这里使用了 long long 数据类型,那么注意输出格式是%lld