返回 课程
信奥AC之路-1级
0% 完成
0/0 步骤
-
第1课 开发环境与基础输出5 主题|小节
-
第2课 算术运算符7 主题|小节
-
第3课 printf与运算输出7 主题|小节
-
第4课 数的进制与拆位6 主题|小节
-
第5课 变量与基础运算17 主题|小节
-
第6课 常量与取整运算8 主题|小节
-
第7课 关系运算8 主题|小节
-
第8课 逻辑运算9 主题|小节
-
第9课 输入与计算进阶10 主题|小节
-
第10课 if语句及双分支语句8 主题|小节
-
第11课 if语句及双分支进阶11 主题|小节
-
第12课 三目运算9 主题|小节
-
第13课 多分支、多if和switch语句11 主题|小节
-
第14课 循环(基本输出)7 主题|小节
-
第15课 循环(While+If)8 主题|小节
-
第16课 循环(计数、求和、求乘积)10 主题|小节
-
第17课 循环进阶(While+)8 主题|小节
-
第18课 do-while及while其他用法8 主题|小节
-
第19课 For循环基础9 主题|小节
-
第20课 For循环进阶8 主题|小节
课 进展
0% 完成
16.1.1 计数的基本概念
“计数就是统计特定条件的数的个数。比如,我们要统计1到100中有多少个偶数,就可以使用循环计数来解决。”
计数的基本思路:
- 定义一个计数变量(通常命名为count或cnt),初始值设为0
- 使用循环遍历所有可能的数
- 在循环中判断每个数是否满足条件,如果满足,计数变量加1
- 循环结束后,计数变量的值就是满足条件的数的个数
16.1.2 实验一:输出1~n中所有的偶数的个数
题目描述: 输入一个正整数n,计算并输出1到n中所有偶数的个数。
样例输入:
10
样例输出:
5
代码实现:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int cnt = 0; // 计数变量初始化为0
int i = 1; // 从1开始循环
while(i <= n) { // 循环到n
if(i % 2 == 0) { // 判断是否为偶数
cnt++; // 计数加1
}
i++; // 循环变量加1
}
cout << cnt; // 输出计数结果
return 0;
}
优化版本:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int cnt = n / 2; // 直接计算偶数个数
cout << cnt; // 输出计数结果
return 0;
}
思考:
- 为什么计数变量cnt的初始值为0?
- 优化版本为什么能直接用n/2计算偶数个数?
解释:
- 计数变量初始化为0,因为一开始我们还没有找到任何偶数。
- 从1到n中,偶数的个数是n/2(如果n是偶数)或(n-1)/2(如果n是奇数)。因为整数除法会向下取整,所以无论n是奇数还是偶数,n/2都能正确计算偶数个数。
16.1.3 实验二:输出m~n中所有的奇数的个数
题目描述: 输入两个正整数m和n(m可能大于n),计算并输出m到n之间(包括m和n)所有奇数的个数。
样例输入:
3 10
样例输出:
4
代码实现:
#include <iostream>
using namespace std;
int main() {
int m, n;
cin >> m >> n;
// 确保m <= n
if(m > n) {
int t = m;
m = n;
n = t;
}
int cnt = 0; // 计数变量初始化为0
int i = m; // 从m开始循环
while(i <= n) { // 循环到n
if(i % 2 != 0) { // 判断是否为奇数
cnt++; // 计数加1
}
i++; // 循环变量加1
}
cout << cnt; // 输出计数结果
return 0;
}
优化版本:
#include <iostream>
using namespace std;
int main() {
int m, n;
cin >> m >> n;
// 确保m <= n
if(m > n) {
int t = m;
m = n;
n = t;
}
// 计算奇数个数
int cnt = (n - m + 1 + (m % 2) ) / 2; // 奇数个数计算公式
cout << cnt; // 输出计数结果
return 0;
}
思考:
- 为什么需要交换m和n的值?
- 优化版本中,奇数个数的计算公式是如何得出的?
解释:
- 因为题目说m可能大于n,但我们需要从较小值遍历到较大值,所以如果m>n,需要交换它们的值。
- 从m到n共有(n-m+1)个数。如果m和n都是奇数,奇数个数为(n-m+1+1)/2;如果m和n都是偶数,奇数个数为(n-m+1)/2;如果一奇一偶,奇数个数为(n-m+1)/2。可以统一表达为(n-m+1+(m%2))/2。
16.1.4 实验三:输出m~n中所有是7的倍数的数的个数
题目描述: 输入两个正整数m和n(保证m <= n),计算并输出m到n之间(包括m和n)是7的倍数的数的个数。
样例输入:
1 50
样例输出:
7
代码实现:
#include <iostream>
using namespace std;
int main() {
int m, n;
cin >> m >> n;
int cnt = 0; // 计数变量初始化为0
int i = m; // 从m开始循环
while(i <= n) { // 循环到n
if(i % 7 == 0) { // 判断是否为7的倍数
cnt++; // 计数加1
}
i++; // 循环变量加1
}
cout << cnt; // 输出计数结果
return 0;
}
优化版本:
#include <iostream>
using namespace std;
int main() {
int m, n;
cin >> m >> n;
// 找到范围内的第一个7的倍数和最后一个7的倍数
int first = (m + 6) / 7 * 7; // 大于等于m的第一个7的倍数
int last = n / 7 * 7; // 小于等于n的最后一个7的倍数
int cnt = 0;
cnt = (last - first) / 7 + 1; // 计算7的倍数的个数
cout << cnt; // 输出计数结果
return 0;
}
思考:
- 对于样例输入1 50,7的倍数有哪些?
- 优化版本中,如何找到范围内的第一个和最后一个7的倍数?
解释:
- 1到50中的7的倍数有:7, 14, 21, 28, 35, 42, 49,共7个。
- 第一个7的倍数可以通过向上取整(m/7)然后乘以7得到,即(m+6)/77;最后一个7的倍数可以通过向下取整(n/7)然后乘以7得到,即n/77。
16.1.5 实验四:输出n的所有因数的个数
题目描述: 输入一个正整数n,计算并输出n的所有因数的个数。
样例输入:
12
样例输出:
6
代码实现:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int cnt = 0; // 计数变量初始化为0
// 正整数的因数最小是1,最大是自己
int i = 1; // 从1开始检查
while(i <= n) { // 检查1到n的所有数
if(n % i == 0) { // 判断i是否为n的因数
cnt++; // 计数加1
}
i++; // 循环变量加1
}
cout << cnt; // 输出计数结果
return 0;
}
优化版本:
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int n;
cin >> n;
int cnt = 0; // 计数变量初始化为0
int i = 1; // 从1开始检查
int sqrtn = sqrt(n); // n的平方根
while(i <= sqrtn) { // 只需要检查到sqrt(n)
if(n % i == 0) { // 判断i是否为n的因数
cnt++; // i是因数,计数加1
if(i != n / i) { // 如果i不等于n/i
cnt++; // n/i也是因数,计数再加1
}
}
i++; // 循环变量加1
}
cout << cnt; // 输出计数结果
return 0;
}
思考:
- 12的所有因数有哪些?
- 优化版本为什么只需要检查到sqrt(n)?
解释:
- 12的因数有:1, 2, 3, 4, 6, 12,共6个。
- 如果i是n的因数,那么n/i也是n的因数。因此,只需要检查到sqrt(n),就能找到所有的因数对(i, n/i)。但需要注意,如果i是n的平方根,则i等于n/i,这种情况下应该只计算一次。
16.1.6 实验五:输出1~n中个位是5的数的个数
题目描述: 输入一个正整数n,计算并输出1到n中个位数字是5的数的个数。
样例输入:
100
样例输出:
10
代码实现:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int cnt = 0; // 计数变量初始化为0
int i = 5; // 从第一个个位是5的数开始
while(i <= n) { // 循环到n
cnt++; // 计数加1
i += 10; // 下一个个位是5的数
}
cout << cnt; // 输出计数结果
return 0;
}
思考:
- 为什么从i=5开始,每次增加10?
- 对于样例输入100,个位是5的数有哪些?
解释:
- 个位是5的数满足i%10=5,这些数分别为5, 15, 25, 35…,所以可以从5开始,每次增加10。
- 1到100中个位是5的数有:5, 15, 25, 35, 45, 55, 65, 75, 85, 95,共10个。
16.1.7 实验六:统计1~n中包含数字3或者5,且因数有2的数的个数
题目描述: 输入一个正整数n(n<1000),计算并输出1到n中包含数字3或者5且是2的倍数的数的个数。
样例输入:
20
样例输出:
2
代码实现(方法一):
#include <iostream>
using namespace std;
int main() {
int i, n, cnt = 0;
cin >> n;
i = 1;
while(i <= n) { // 从1开始检查每个数
int g = i % 10; // 个位
int s = i / 10 % 10; // 十位
int b = i / 100 % 10; // 百位
// 判断是否为2的倍数且包含数字3或5
if(i % 2 == 0 && (g == 5 || g == 3 || s == 5 || s == 3 || b == 5 || b == 3)) {
cnt++; // 计数加1
}
i++; // 检查下一个数
}
cout << cnt; // 输出计数结果
return 0;
}
代码实现(方法二):
#include <iostream>
using namespace std;
int main() {
int i, n, cnt = 0;
cin >> n;
i = 2;
while(i <= n) { // 直接从2开始,只检查偶数
int g = i % 10; // 个位
int s = i / 10 % 10; // 十位
int b = i / 100 % 10; // 百位
// 只需判断是否包含数字3或5
if(g == 5 || g == 3 || s == 5 || s == 3 || b == 5 || b == 3) {
cnt++; // 计数加1
}
i += 2; // 增加2,跳到下一个偶数
}
cout << cnt; // 输出计数结果
return 0;
}
思考:
- 两种方法在实现上有什么区别?哪种更高效?
- 为什么方法二可以直接从2开始,每次增加2?
- 对于样例输入20,有哪些数同时满足这两个条件?
解释:
- 方法一检查从1到n的每个数,然后用条件语句筛选出符合要求的数;方法二只检查偶数(从2开始,每次加2),这样就不需要额外判断是否为2的倍数。方法二更高效,因为它减少了循环次数(大约减少一半)和判断次数。
- 方法二从2开始,每次增加2,保证了所有检查的数都是偶数(即2的倍数)。由于题目要求数是2的倍数,这种方法避免了对非偶数的不必要检查,提高了效率。
16.1.8 实验七:输出m~n中所有的闰年的个数
题目描述: 输入两个正整数m和n(保证m < n),计算并输出m到n之间(不包括m和n)所有闰年的个数。
样例输入:
2000 2020
样例输出:
4
代码实现:
#include <iostream>
using namespace std;
int main() {
int m, n;
cin >> m >> n;
int cnt = 0; // 计数变量初始化为0
int i = m + 1; // 从m后面的一年开始循环
while(i < n) { // 循环到n前面的一年
// 判断是否为闰年
if((i % 4 == 0 && i % 100 != 0) || i % 400 == 0) {
cnt++; // 计数加1
}
i++; // 循环变量加1
}
cout << cnt; // 输出计数结果
return 0;
}
思考:
- 闰年的判断条件是什么?
- 为什么循环从m+1开始到n-1结束?
- 对于样例输入2000 2020,有哪些年份被计算在内?哪些年份不被计算?
解释:
- 闰年的判断条件是:(1)能被4整除但不能被100整除,或(2)能被400整除。
- 循环从m+1开始到n-1结束是因为题目要求不包括边界值m和n,只计算它们之间的闰年个数。
- 对于输入2000 2020,计算的年份范围是2001到2019。其中闰年有:2004、2008、2012、2016,共4个。而2000和2020虽然也是闰年,但根据题目要求不计算在内。