精选95道洛谷入门~提高组经典题目,覆盖CSP-J/S 2025/2026 完整考纲。每道题都包含:完整题目描述 + 算法思路剖析 + 带行号的高亮代码 + 逐行深度讲解 + 薛老师建议。让学生看一遍就能理解算法,写出代码!
这道题是NOIP2005普及组的第一题,考察最基本的数组读取、循环遍历和条件判断。核心思路非常直观:把10个苹果的高度存到数组里,然后拿陶陶能到达的最大高度(自身高度+板凳30cm)和每个苹果比较,统计高度≤陶陶可达高度的苹果数量。
这道题非常适合作为C++入门后的第一道算法题。先让学生在纸上画出10个苹果和陶陶站板凳的示意图,然后引导他们思考"怎么比较"。鼓励学生先写伪代码再写C++代码。完成打字后,可以让学生尝试改编——比如苹果数量不固定为10个,改成由输入决定。
#include <iostream>
using namespace std;
int main() {
int apple[10];
int height;
for (int i = 0; i < 10; i++) {
cin >> apple[i];
}
cin >> height;
height += 30;
int cnt = 0;
for (int i = 0; i < 10; i++) {
if (apple[i] <= height) {
cnt++;
}
}
cout << cnt << endl;
return 0;
}
这道题的本质是"在序列中找最长的连续递增子段"。核心技巧是设置两个变量:curLen(当前连续长度)和maxLen(历史最大长度)。遍历时只需判断"当前数是否等于前一个数+1",如果是则curLen++,否则curLen重置为1。每次更新curLen后比较是否超过maxLen即可。时间复杂度O(n),只需遍历一遍。
这道题考验学生的"状态追踪"思维——在遍历过程中同时维护多个变量(prev/curLen/maxLen)。建议先让学生理解"一次遍历必须记录哪些信息",用表格在纸上模拟:当读到每个数时,curLen变成多少?maxLen要不要更新?让学生用笔写一遍模拟过程,比直接写代码更快理解。
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int prev, curr;
cin >> prev;
int maxLen = 1;
int curLen = 1;
for (int i = 1; i < n; i++) {
cin >> curr;
if (curr == prev + 1) {
curLen++;
} else {
curLen = 1;
}
if (curLen > maxLen) {
maxLen = curLen;
}
prev = curr;
}
cout << maxLen << endl;
return 0;
}
数字反转的经典套路:用 while(n>0) { digit=n%10; rev=rev*10+digit; n/=10; } 循环逐位提取并重组。有两个关键细节:(1)负数的处理——先输出负号再取绝对值;(2)末尾零的处理——反转后不能出现前导零,所以需要先把末尾0去掉再反转,或者在反转过程中处理。本题采用"先去掉末尾0再反转"的策略,更直观。
数位处理是CSP-J的常考点。让学生理解n%10取最后一位、n/10去掉最后一位这两个操作,可以用"剥洋葱"来比喻——每次剥掉最外面一层(最后一位)。这道题如果不先处理末尾0,直接反转会得到021这样的结果,这正是教学的好时机:什么样的结果是合法的整数?
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
if (n < 0) {
cout << "-";
n = -n;
}
while (n > 0 && n % 10 == 0) {
n /= 10;
}
int rev = 0;
while (n > 0) {
int digit = n % 10;
rev = rev * 10 + digit;
n /= 10;
}
if (rev == 0) cout << 0;
else cout << rev;
cout << endl;
return 0;
}
🔥 想把这些代码真正练熟?去 打字练习 页面逐字符敲一遍,形成肌肉记忆!