快捷键

切换暗色模式 CtrlD
搜索 CtrlK
关闭弹窗 Esc
返回顶部 Ctrl
快捷键面板 Ctrl/
C++信息学奥赛打字闯关
首页 闯关训练 段位系统 题库中心
技术博客 新闻资讯
排行榜 信奥社区 成就殿堂 在线留言 AI助手

📚 洛谷经典题目 · 超详细算法详解

精选95道洛谷入门~提高组经典题目,覆盖CSP-J/S 2025/2026 完整考纲。每道题都包含:完整题目描述 + 算法思路剖析 + 带行号的高亮代码 + 逐行深度讲解 + 薛老师建议。让学生看一遍就能理解算法,写出代码!

95
经典题目
5级
难度梯度
15类
算法主题
2025
CSP对标
1

陶陶摘苹果 P1046

入门 算法:简单模拟 1.00s / 125.00MB
数组 模拟 循环

📖题目描述

陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 10 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 30 厘米 高的板凳,当她不能直接用手摘到苹果时,就会踩到板凳上再试试。

现在已知 10 个苹果 距离地面的高度,以及陶陶把手伸直时能够达到的最大高度。请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。

📋输入 / 输出格式

第一行:10 个整数(100 ≤ 每个整数 ≤ 200),分别表示 10 个苹果距离地面的高度。 第二行:一个整数(100 ≤ 整数 ≤ 120),表示陶陶把手伸直时能达到的最大高度。 一个整数,表示陶陶能够摘到的苹果的数量。
样例输入 100 200 150 140 129 134 167 198 200 111 110
样例输出 5

🧠算法分析

💡 核心思想

这道题是NOIP2005普及组的第一题,考察最基本的数组读取、循环遍历和条件判断。核心思路非常直观:把10个苹果的高度存到数组里,然后拿陶陶能到达的最大高度(自身高度+板凳30cm)和每个苹果比较,统计高度≤陶陶可达高度的苹果数量。

🎯 考点分析
  • 1. 数组的定义和初始化 int apple[10]
  • 2. for循环读取数组元素 cin >> apple[i]
  • 3. 别忘了加板凳高度 height += 30
  • 4. 用计数器统计满足条件的元素个数
  • 5. 输出结果 cout << cnt
📝 薛老师建议

这道题非常适合作为C++入门后的第一道算法题。先让学生在纸上画出10个苹果和陶陶站板凳的示意图,然后引导他们思考"怎么比较"。鼓励学生先写伪代码再写C++代码。完成打字后,可以让学生尝试改编——比如苹果数量不固定为10个,改成由输入决定。

💻完整代码(带行号语法高亮)

P1046 - 陶陶摘苹果 C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
#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;
}

🔍逐行深度讲解

2

最长连号 P1420

入门 算法:线性遍历+计数 1.00s / 125.00MB
循环 条件判断 滑动窗口

📖题目描述

输入一个正整数 n(1 ≤ n ≤ 10000),然后是 n 个正整数,请找出这 n 个数中最长的连续自然数序列的长度。

比如输入 n=7 个数: 1 5 6 2 3 4 7,其中最长连续递增子段是 2 3 45 6,最长的连续序列长度是 3。

📋输入 / 输出格式

第一行:一个整数 n,表示接下来有 n 个整数。 第二行:n 个正整数。 一个整数,表示最长连续自然数序列的长度。
样例输入 7 1 5 6 2 3 4 7
样例输出 3

🧠算法分析

💡 核心思想

这道题的本质是"在序列中找最长的连续递增子段"。核心技巧是设置两个变量:curLen(当前连续长度)和maxLen(历史最大长度)。遍历时只需判断"当前数是否等于前一个数+1",如果是则curLen++,否则curLen重置为1。每次更新curLen后比较是否超过maxLen即可。时间复杂度O(n),只需遍历一遍。

🎯 考点分析
  • 1. 先单独读第一个数作为prev
  • 2. curLen和maxLen初始化为1(一个数自身也是长度为1的连号)
  • 3. 判断条件 curr == prev + 1 是核心
  • 4. 每次循环末尾更新 prev = curr
  • 5. ★ 注意存储中间最大值的过程:每步都检查if(curLen > maxLen)
📝 薛老师建议

这道题考验学生的"状态追踪"思维——在遍历过程中同时维护多个变量(prev/curLen/maxLen)。建议先让学生理解"一次遍历必须记录哪些信息",用表格在纸上模拟:当读到每个数时,curLen变成多少?maxLen要不要更新?让学生用笔写一遍模拟过程,比直接写代码更快理解。

💻完整代码(带行号语法高亮)

P1420 - 最长连号 C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#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;
}

🔍逐行深度讲解

3

数字反转 P1307

入门 算法:数位拆分与重组 1.00s / 125.00MB
数位处理 循环 while

📖题目描述

给定一个整数 N(-10⁹ ≤ N ≤ 10⁹),请将该数各个数位上的数字反转得到一个新数。反转后新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后新数的最高位数字不应为零。

例如:输入 380,输出 83(而不是 083);输入 -290,输出 -92。

📋输入 / 输出格式

一个整数 N。 一个整数,表示反转后的新数。
样例输入 380
样例输出 83

🧠算法分析

💡 核心思想

数字反转的经典套路:用 while(n>0) { digit=n%10; rev=rev*10+digit; n/=10; } 循环逐位提取并重组。有两个关键细节:(1)负数的处理——先输出负号再取绝对值;(2)末尾零的处理——反转后不能出现前导零,所以需要先把末尾0去掉再反转,或者在反转过程中处理。本题采用"先去掉末尾0再反转"的策略,更直观。

🎯 考点分析
  • 1. 负数处理:先输出"-",再 n = -n
  • 2. 取个位:n % 10
  • 3. 去掉个位:n /= 10
  • 4. ★ 拼接反转数:rev = rev * 10 + digit
  • 5. 末尾0陷阱:反转前需要消除
  • 6. n=0的边界情况
📝 薛老师建议

数位处理是CSP-J的常考点。让学生理解n%10取最后一位、n/10去掉最后一位这两个操作,可以用"剥洋葱"来比喻——每次剥掉最外面一层(最后一位)。这道题如果不先处理末尾0,直接反转会得到021这样的结果,这正是教学的好时机:什么样的结果是合法的整数?

💻完整代码(带行号语法高亮)

P1307 - 数字反转 C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#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;
}

🔍逐行深度讲解

🔒 剩余 92 道题目需要登录后查看

游客可查看前 3 道题。登录后免费解锁 20 道,成为 VIP 会员解锁全部 95 道!

🔐 登录/注册(解锁20道)
📚
95 道题
全部题目解锁
🎯
CSP-J/S 对标
完整考纲覆盖
💡
逐行讲解
每行代码深度解析

🔥 想把这些代码真正练熟?去 打字练习 页面逐字符敲一遍,形成肌肉记忆!

在线

给管理员留言

每条留言老师都会认真阅读并回复

📚 课程咨询 🔧 技术求助 💡 建议反馈 🤝 合作联系

留言发送成功!

您的留言已送达管理员后台

追踪码(请保存以便查询回复)
------