16.2.1 求和的基本概念
“求和就是计算多个数的总和。比如,我们要计算1到100中所有偶数的和,就可以使用循环求和来解决。”
求和的基本思路:
- 定义一个求和变量(通常命名为sum),初始值设为0
- 使用循环遍历所有可能的数
- 在循环中判断每个数是否满足条件,如果满足,将该数加入到求和变量中
- 循环结束后,求和变量的值就是满足条件的数的总和
16.2.2 实验一:输出1~n中所有的偶数的和
题目描述: 输入一个正整数n,计算并输出1到n中所有偶数的和。
样例输入:
10
样例输出:
30
代码实现:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int sum = 0; // 总和变量初始化为0
int i = 2; // 从第一个偶数2开始
while(i <= n) { // 循环到n
sum += i; // 加到总和中
i += 2; // 增加2,保持i为偶数
}
cout << sum; // 输出总和
return 0;
}
优化版本:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
// 计算偶数和的公式:2+4+6+...+2k = 2(1+2+3+...+k) = 2*k*(k+1)/2,其中k=n/2
int k = n / 2; // 计算有多少个偶数
int sum = k * (k + 1); // 计算偶数和
cout << sum; // 输出总和
return 0;
}
思考:
- 为什么sum的初始值设为0?
- 对于样例输入10,偶数有哪些?它们的和是多少?
解释:
- sum初始化为0是因为一开始我们还没有加入任何数,总和为0。
- 1到10中的偶数有:2, 4, 6, 8, 10,共5个,总和为2+4+6+8+10=30。
16.2.3 实验二:输出m~n中所有的奇数的和
题目描述: 输入两个正整数m和n(保证m <= n),计算并输出m到n之间(包括m和n)所有奇数的和。
样例输入:
1 10
样例输出:
25
代码实现:
#include <iostream>
using namespace std;
int main() {
int m, n;
cin >> m >> n;
int sum = 0; // 总和变量初始化为0
// 调整m为第一个奇数
if(m % 2 == 0) {
m++; // 如果m是偶数,调整为下一个奇数
}
int i = m; // 从第一个奇数开始
while(i <= n) { // 循环到n
sum += i; // 加到总和中
i += 2; // 增加2,保持i为奇数
}
cout << sum; // 输出总和
return 0;
}
思考:
- 代码如何确保只计算奇数的和?
- 对于样例输入1 10,奇数有哪些?它们的和是多少?
解释:
- 首先调整m为第一个奇数(如果m本身是偶数,则加1),然后每次递增2,确保i始终是奇数。
- 1到10中的奇数有:1, 3, 5, 7, 9,共5个,总和为1+3+5+7+9=25。
16.2.4 实验三:输出m~n中所有是7的倍数的数的和
题目描述: 输入两个正整数m和n(保证m <= n),计算并输出m到n之间(包括m和n)是7的倍数的数的和。
样例输入:
1 50
样例输出:
196
代码实现:
#include <iostream>
using namespace std;
int main() {
int m, n;
cin >> m >> n;
int sum = 0; // 总和变量初始化为0
// 找到第一个大于等于m的7的倍数
int i = m;
if(i % 7 != 0) {
i = i + (7 - i % 7); // 调整为下一个7的倍数
}
while(i <= n) { // 循环到n
sum += i; // 加到总和中
i += 7; // 增加7,保持i为7的倍数
}
cout << sum; // 输出总和
return 0;
}
思考:
- 代码如何找到第一个大于等于m的7的倍数?
- 对于样例输入1 50,7的倍数有哪些?它们的和是多少?
解释:
- 如果m本身不是7的倍数,我们需要找到下一个7的倍数。通过计算m % 7得到余数,然后加上(7 – 余数)就能得到下一个7的倍数。
- 1到50中的7的倍数有:7, 14, 21, 28, 35, 42, 49,共7个,总和为7+14+21+28+35+42+49=196。
16.2.5 实验四:输出n的所有因数的和
题目描述: 输入一个正整数n,计算并输出n的所有因数的和。
样例输入:
12
样例输出:
28
代码实现:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int sum = 0; // 总和变量初始化为0
int i = 1; // 从1开始检查
while(i <= n) { // 检查1到n的所有数
if(n % i == 0) { // 判断i是否为n的因数
sum += i; // 加到总和中
}
i++; // 循环变量加1
}
cout << sum; // 输出总和
return 0;
}
优化版本:
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int n;
cin >> n;
int sum = 0; // 总和变量初始化为0
int i = 1; // 从1开始检查
int sqrtn = sqrt(n); // n的平方根
while(i <= sqrt(n)) { // 只需要检查到sqrt(n)
if(n % i == 0) { // 判断i是否为n的因数
sum += i; // i是因数,加到总和中
if(i != n / i) { // 如果i不等于n/i
sum += (n / i); // n/i也是因数,也加到总和中
}
}
i++; // 循环变量加1
}
cout << sum; // 输出总和
return 0;
}
思考:
- 12的所有因数有哪些?它们的和是多少?
- 优化版本如何减少循环次数?
解释:
- 12的因数有:1, 2, 3, 4, 6, 12,共6个,总和为1+2+3+4+6+12=28。
- 如果i是n的因数,那么n/i也是n的因数。通过只检查到sqrt(n)并同时处理因数对(i, n/i),可以显著减少循环次数。
16.2.6 实验五:输出m~n中所有的闰年的和
题目描述: 输入两个正整数m和n(保证m <= n),计算并输出m到n之间(包括m和n)所有闰年的年份的和。
样例输入:
2000 2020
样例输出:
12060
代码实现:
#include <iostream>
using namespace std;
int main() {
int m, n;
cin >> m >> n;
int sum = 0; // 总和变量初始化为0
int i = m; // 从m开始循环
while(i <= n) { // 循环到n
// 判断是否为闰年
if((i % 4 == 0 && i % 100 != 0) || i % 400 == 0) {
sum += i; // 加到总和中
}
i++; // 循环变量加1
}
cout << sum; // 输出总和
return 0;
}
思考:
- 对于样例输入2000 2020,闰年有哪些?它们的年份和是多少?
- 使用什么方法可以直接计算特定范围内的闰年和?
解释:
- 2000(能被400整除)、2004、2008、2012、2016、2020(能被4整除但不能被100整除)均为闰年,年份和为2000+2004+2008+2012+2016+2020=12060。
- 目前没有简单的数学公式可以直接计算闰年和,因为闰年的判断条件较为复杂,需要逐一检查。
16.2.7 实验六:计算1~n中是2的倍数或者是3的倍数的数的总和
题目描述: 输入一个正整数n,计算并输出1到n中所有是2的倍数或者是3的倍数的数的总和。
样例输入:
10
样例输出:
42
代码实现(方法一):
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int sum = 0; // 总和变量初始化为0
int i = 1; // 从1开始循环
while(i <= n) { // 循环到n
if(i % 2 == 0 || i % 3 == 0) { // 判断是否为2的倍数或3的倍数
sum += i; // 加到总和中
}
i++; // 循环变量加1
}
cout << sum; // 输出总和
return 0;
}
代码实现(方法二):
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int sum = 0; // 总和变量初始化为0
int i = 1; // 从1开始循环
while(i <= n) { // 循环到n
if(i % 2 == 0) { // 判断是否为2的倍数
sum += i; // 加到总和中
} else if(i % 3 == 0) { // 如果不是2的倍数但是3的倍数
sum += i; // 加到总和中
}
i++; // 循环变量加1
}
cout << sum; // 输出总和
return 0;
}
思考:
- 两种方法的区别和优缺点是什么?
- 对于样例输入10,哪些数是2的倍数或3的倍数?它们的和是多少?
解释:
- 方法一使用逻辑或(||)操作直接判断是否满足条件,代码简洁明了。方法二使用if-else if结构,分别处理2的倍数和只是3的倍数的情况,逻辑更清晰但效率相同。
- 1到10中,2的倍数有:2, 4, 6, 8, 10;3的倍数有:3, 6, 9。去重后,符合条件的数有:2, 3, 4, 6, 8, 9, 10,总和为2+3+4+6+8+9+10=42。
16.2.8 实验七:计算1~n中所有是5的倍数并且包含数字5的数的总和
题目描述: 输入一个正整数n(n<1000),计算并输出1到n中所有既是5的倍数又包含数字5的数的总和。
样例输入:
100
样例输出:
50
代码实现:(方法一)
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int sum = 0; // 总和变量初始化为0
int i = 1; // 从5开始循环(第一个5的倍数)
while(i <= n) { // 循环到n
int g = i % 10; // 个位
int s = i / 10 % 10; // 十位
int b = i / 100 % 10; // 百位
if(i % 5 == 0 && (g == 5 || s == 5 || b == 5)) { // 判断是否为5的倍数并且包含5
sum += i; // 加到总和中
}
i++;
}
cout << sum; // 输出总和
return 0;
}
代码实现(方法二):
#include <iostream>
using namespace std;
int main() {
int i, n, sum = 0; // 定义变量i、n和总和sum
cin >> n; // 输入整数n
i = 1; // 初始化i为1
while(i <= n) { // 循环遍历1到n
int g = i % 10; // 获取i的个位数字
int s = i / 10 % 10; // 获取i的十位数字
int b = i / 100 % 10; // 获取i的百位数字
if(i % 5 == 0) { // 判断i是否为5的倍数
if(g == 5) { // 判断个位是否为5
sum += i; // 将i加到总和中
}else if( s== 5){ // 判断十位是否为5
sum += i; // 将i加到总和中
}else if(b == 5){ // 判断百位是否为5
sum += i; // 将i加到总和中
}
}
i++; // i自增1
}
cout << sum; // 输出总和
return 0;
}
代码实现(方法三):
#include <iostream>
using namespace std;
int main() {
int i, n, sum = 0; // 定义变量i、n和总和sum
cin >> n; // 输入整数n
i = 1; // 初始化i为1
while(i <= n) { // 循环遍历1到n
// 判断i是否为5的倍数且包含数字5
if(i % 5 == 0) { // 判断i是否为5的倍数
int g = i % 10; // 获取i的个位数字
int s = i / 10 % 10; // 获取i的十位数字
int b = i / 100 % 10; // 获取i的百位数字
if(g == 5 || s == 5 || b == 5) { // 判断是否包含数字5
sum += i; // 将i加到总和中
}
}
i++; // i自增1
}
cout << sum; // 输出总和
return 0;
}
代码实现(方法四):
#include <iostream>
using namespace std;
int main() {
int i, n, sum = 0; // 定义变量i、n和总和sum
cin >> n; // 输入整数n
i = 5; // 初始化i为5,第一个满足条件的数
while(i <= n) { // 循环遍历符合条件的数
int g = i % 10; // 获取i的个位数字
int s = i / 10 % 10; // 获取i的十位数字
int b = i / 100 % 10; // 获取i的百位数字
// 判断是否包含数字5
if(g == 5 || s == 5 || b == 5) {
sum += i; // 将i加到总和中
}
i += 5; // i增加5,保持是5的倍数
}
cout << sum; // 输出总和
return 0;
}
思考:
每种写法循环的次数和判断是如何执行的
16.2.9 实验八:计算1~n中是3的倍数的奇数的总和
题目描述: 输入一个正整数n,计算并输出1到n中所有是3的倍数且为奇数的数的总和。
样例输入:
20
样例输出:
30
代码实现(方法一):
#include <iostream>
using namespace std;
int main() {
int i, n, sum = 0; // 定义变量i、n和总和sum
cin >> n; // 输入整数n
i = 1; // 初始化i为1
while(i <= n) { // 循环遍历1到n
if(i % 2 != 0 && i % 3 == 0) { // 判断i是否为奇数且是3的倍数
sum += i; // 将符合条件的数加到总和中
}
i++; // i自增1
}
cout << sum; // 输出总和
return 0;
}
代码实现(方法二):
#include <iostream>
using namespace std;
int main() {
int i, n, sum = 0; // 定义变量i、n和总和sum
cin >> n; // 输入整数n
i = 1; // 初始化i为1
while(i <= n) { // 循环遍历1到n
if(i % 2 != 0) { // 判断i是否为奇数
if(i % 3 == 0) { // 判断i是否为3的倍数
sum += i; // 将符合条件的数加到总和中
}
}
i++; // i自增1
}
cout << sum; // 输出总和
return 0;
}
代码实现(方法三):
#include <iostream>
using namespace std;
int main() {
int i, n, sum = 0; // 定义变量i、n和总和sum
cin >> n; // 输入整数n
i = 3; // 初始化i为3,第一个奇数且是3的倍数的数
while(i <= n) { // 循环遍历符合条件的数
sum += i; // 将i加到总和中
i += 6; // i增加6,跳到下一个奇数且是3的倍数的数
}
cout << sum; // 输出总和
return 0;
}
思考:
- 三种方法的运行过程及优点是什么?
- 为什么方法三从3开始,每次增加6?
解释:
- 方法一使用两个条件判断,直接判断是否为奇数且是3的倍数;方法二使用嵌套判断,先判断奇数再判断是否为3的倍数;方法三直接从第一个符合条件的数(3)开始,每次增加6,不需要额外判断条件。
- 方法三从3开始是因为3是第一个既是奇数又是3的倍数的数。每次增加6是因为3的倍数中,相邻的奇数之间的间隔是6(如3, 9, 15…)。因为偶数个3的倍数是偶数,奇数个3的倍数是奇数,所以奇数的3倍数需要间隔6。