← 目录 第 1 / 60 节 全部 60 节

01 · 输入输出与评测机制

把“题目 → 代码”这条最短链路打通:知道评测机在比什么,掌握 cin/cout 的结构与用法,并第一次建立“数据范围决定变量类型”的意识。
⭐ 已学范围入门预计 45 分钟cin/coutgetline整数范围评测机制
本节出现的新函数 / 新语法(先看懂再用)

先接受一个事实:评测机不理解你的程序,它只做一件事——把你输出的字节和标准答案的字节逐字比对。所以从第一天起,你写的每一行输出都要能回答一个问题:它会不会出现在标准答案里?

例题 · A+B Problem洛谷 P1001入门去洛谷做这题 ↗

输入两个整数 a、b(|a|,|b| ≤ 10⁹),输出它们的和。

输入: 2 3 输出: 5

这一节会出现 4 个必须彻底搞懂的东西。先把它们的“结构”拆开看清,后面所有代码都靠它们。

新函数拆解 · cin(标准输入流)
std::cin >> 变量1 >> 变量2 >> ...;
组成含义 / 格式要求
std::cin标准输入流对象,代表“键盘/文件”。程序中只有一个,直接拿来用。
>>提取运算符:把输入里的下一个“词”取出来,放进右边变量。
链式写法 cin >> a >> b 等价于 (cin>>a)>>b,读第一个数给 a,读第二个给 b。
跳过空白自动跳过空格、Tab、换行,所以数据分行写也能正确读入。
类型自动匹配给 int 读整数,给 double 读小数,给 char 读一个非空白字符。
最小可运行示例
示例
#include <iostream>          // cin / cout 都在这个头文件
using namespace std;     // 展开 std 命名空间,之后可以直接写 cin

int main() {
    int a, b;
    cin >> a >> b;       // 一次读两个整数
    cout << a + b;
    return 0;
}
注意

读入类型必须和变量类型一致:给 int 变量输入“abc”,cin 会失败并让后续读入全部失效。

cin 不会检查你有没有读够。数据比预期少时,后面的变量保持原值(局部变量是随机值)。

新函数拆解 · cout(标准输出流)
std::cout << 内容1 << 内容2 << ...;
组成含义 / 格式要求
std::cout标准输出流对象,代表“屏幕/文件”。
<<插入运算符:把右边的内容转成字符,送进输出流。
'\n'换行符,一个字符,不刷新缓冲区,速度最快。
endl换行 + 立刻刷新缓冲区。循环里大量用会慢 3~10 倍。
格式控制cout << fixed << setprecision(2) 固定两位小数,需要 #include 。
最小可运行示例
示例
cout << a << " " << b << "\n";     // 输出 a、空格、b、换行
cout << "ans = " << ans << "\n";    // 文字和数字可以混着插
cout << fixed << setprecision(3) << 1.0 / 3;   // 0.333
注意

cout 不需要写格式符(不像 printf 要 %d、%lf),类型对就行。

循环十万次以上时,用 '\n' 而不是 endl。

新函数拆解 · ios::sync_with_stdio(false) 与 cin.tie(nullptr)
ios::sync_with_stdio(false); cin.tie(nullptr);
组成含义 / 格式要求
sync_with_stdio(false)关闭 C 流(scanf/printf)与 C++ 流(cin/cout)的同步。关掉后 cin 快 3~5 倍。副作用:此后不能再混用 scanf 和 cin。
cin.tie(nullptr)解除 cin 对 cout 的绑定。默认每次 cin 前会先刷新 cout,解除后少一次刷新,更快。
放在哪必须写在 main 开头、任何输入输出之前,写一次就够。
最小可运行示例
示例
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n; cin >> n;              // 读 10^6 个数也不会慢
    for (int i = 0; i < n; ++i) { int x; cin >> x; }
    return 0;
}
注意

只有输入量很大(≥ 10⁵ 个数)时才明显有用,但养成习惯没坏处。

关同步后不要再用 scanf/printf,否则读写顺序会乱。

新函数拆解 · getline(读入一整行)
std::getline(std::cin, s);
组成含义 / 格式要求
std::cin从哪个流读。
sstring 变量,读到的整行内容存这里(不含结尾的换行符)。
读到哪里停读到 '\n' 为止,并且把 '\n' 从流里取走丢掉。
常见搭配当输入含空格时必须用它;cin >> 只会读到一个“词”。
最小可运行示例
示例
string line;
getline(cin, line);              // "hello world" 整行读进来

int n; cin >> n;
cin.ignore();                    // ★ 先吃掉 n 后面残留的换行
getline(cin, line);              // 否则这里读到的是空串
注意

cin >> n 之后直接 getline,会读到空串——因为换行还留在缓冲区里。

解决办法:中间插一句 cin.ignore()。

例题怎么想:把题目翻译成 3 行代码

题目要做的事只有一件:读两个数,加起来,输出。

所以代码必然是三段:声明变量 → 读入 → 计算并输出。先把这三段写出来,再考虑细节。

完整代码
#include <iostream>
using namespace std;

int main() {
    int a, b;              // ① 声明:两个整数变量,初始是随机值
    cin >> a >> b;         // ② 读入:按顺序把前两个数放进 a、b
    cout << a + b << "\n"; // ③ 计算并输出,末尾换行
    return 0;
}
逐行拆解
代码片段含义与理由
#include <iostream>引入输入输出库。没有它,cin/cout 都不存在,编译报错。
using namespace std;把 std 命名空间展开,于是能写 cin 而不是 std::cin。竞赛里人人这么写。
int main()程序入口。评测系统从这里开始执行,return 的值表示是否正常结束。
int a, b;两个 32 位整数。范围 ±2.1×10⁹,本题 |a|,|b| ≤ 10⁹ 够用。
cin >> a >> b;先读第一个数给 a,再读第二个数给 b。空格、换行都会被自动跳过。
cout << a + b << "\n";先算 a+b,再把结果转成字符串插入输出流,最后换行。
return 0;告诉评测系统“正常结束”。不写多数编译器也会补,但建议写。
这一节最容易犯的 4 个错

输出提示语。写 cout << "请输入两个数:" 会直接 WA——因为这句话会被当成答案的一部分。

用 int 存超出范围的结果。本题 a+b 最大 2×10⁹,刚好卡在 int 上限(2.147×10⁹)附近;题目若改成 10¹⁸ 就必须用 long long。

忘记换行。多数题对行末换行不敏感,但有些题严格比对,养成加 "\n" 的习惯。

多打空格。行末多一个空格,严格评测(如 NOIP)会判 WA。

自己动手复现

把上面的完整代码不看页面敲一遍,提交到 P1001。

然后把输入改成 1000000000 1000000000,看输出是否为 2000000000。

如果输出是负数,说明你把变量改成了 short —— 亲手体验一次溢出。

数学补给 · 为什么 int 的上限是 2.1×10⁹

int 占 4 字节 = 32 位。其中 1 位是符号位,剩下 31 位表示大小。

最大值 = 2³¹ − 1 = 2147483647 ≈ 2.14×10⁹。最小值 = −2³¹ = −2147483648。

类型字节范围十进制位数
int4±2.14×10⁹10 位
long long8±9.22×10¹⁸19 位
unsigned long long80 ~ 1.84×10¹⁹20 位

记住“19”这个数:long long 最多表示 19 位十进制整数。超过 19 位就必须用高精度(字符串/数组模拟)。

推论:只要题目里出现“求和”“相乘”,先用草稿纸估一下最坏情况是多少,超过 2×10⁹ 立刻换 long long。

举一反三 · 想清楚这些再往下走
  1. 如果题目要求“先输出 a,再输出 b,中间用逗号分隔、行末不要空格”,cout 那句该怎么写?试着只改一行。
  2. 把 int 换成 double 读入 1 2,输出会变成什么样?为什么会多出小数?
  3. 如果输入是“10 个数,每行一个”,用 cin >> x 循环 10 次能正确读入吗?为什么?
  4. 为什么 endl 会比 "\n" 慢?慢在哪一步?
  5. 评测机是怎么比较你的输出和标准答案的?它会不会忽略多余空格?
自测:能全部回答再进下一节
挑战题 · 小鱼的游泳时间
洛谷 P1425入门去洛谷做这题 ↗

小鱼从 a 时 b 分游到 c 时 d 分,中间没有休息。求它一共游了多少小时多少分钟。

输入一行 4 个整数 a、b、c、d(0 ≤ a,c ≤ 24,0 ≤ b,d ≤ 59),保证结束时刻晚于开始时刻。

输出一行两个整数,表示共游的小时数和分钟数。

引导性提示(先只看这里)

不要“小时减小时、分钟减分钟”,那样会遇到分钟不够减的情况。

把所有时间先统一换成“从 0 点开始算的第几分钟”,相减后再拆回小时和分钟。

拆法:总分钟 ÷ 60 得到小时,总分钟 % 60 得到分钟。

想看思路了?点开完整思路

开始时刻 = a × 60 + b(分钟)。结束时刻 = c × 60 + d。

总时长 = 结束 − 开始。

输出 总时长 / 60 和 总时长 % 60。

为什么这样一定对:分钟制是一个“统一单位”,换算后相减等价于时间差,不受进位影响。

还是不会?点开题解代码与拆解
参考代码
#include <iostream>
using namespace std;

int main() {
    int a, b, c, d;
    cin >> a >> b >> c >> d;

    int start = a * 60 + b;      // 开始时刻换算成分钟
    int end   = c * 60 + d;      // 结束时刻换算成分钟
    int span  = end - start;     // 总时长(分钟)

    cout << span / 60 << " " << span % 60 << "\n";
    return 0;
}
关键片段拆解
片段作用
a * 60 + b把“a 时 b 分”压成一个整数。这一步把二维的时间变成一维的数,后面就能直接相减。
end - start统一单位后相减一定正确,不用管分钟借位。
span / 60整数除法,向下取整,正好是完整的小时数。
span % 60余数就是不足一小时的分钟数。
<< " " <<两个数之间用一个空格隔开,行末只换行不加空格。
这题最容易错的地方
  • 图省事写成 d - b 和 c - a,遇到 “1 50 → 2 20” 这种分钟不够减的情况就错。
  • 用 %02d 输出前导零——题目没要求,输出 01 会 WA。
  • 忘了最后换行。
延伸阅读 / 参考