先接受一个事实:评测机不理解你的程序,它只做一件事——把你输出的字节和标准答案的字节逐字比对。所以从第一天起,你写的每一行输出都要能回答一个问题:它会不会出现在标准答案里?
这一节会出现 4 个必须彻底搞懂的东西。先把它们的“结构”拆开看清,后面所有代码都靠它们。
| 组成 | 含义 / 格式要求 |
|---|---|
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 不会检查你有没有读够。数据比预期少时,后面的变量保持原值(局部变量是随机值)。
| 组成 | 含义 / 格式要求 |
|---|---|
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.333cout 不需要写格式符(不像 printf 要 %d、%lf),类型对就行。
循环十万次以上时,用 '\n' 而不是 endl。
| 组成 | 含义 / 格式要求 |
|---|---|
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,否则读写顺序会乱。
| 组成 | 含义 / 格式要求 |
|---|---|
std::cin | 从哪个流读。 |
s | string 变量,读到的整行内容存这里(不含结尾的换行符)。 |
读到哪里停 | 读到 '\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()。
题目要做的事只有一件:读两个数,加起来,输出。
所以代码必然是三段:声明变量 → 读入 → 计算并输出。先把这三段写出来,再考虑细节。
#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; | 告诉评测系统“正常结束”。不写多数编译器也会补,但建议写。 |
输出提示语。写 cout << "请输入两个数:" 会直接 WA——因为这句话会被当成答案的一部分。
用 int 存超出范围的结果。本题 a+b 最大 2×10⁹,刚好卡在 int 上限(2.147×10⁹)附近;题目若改成 10¹⁸ 就必须用 long long。
忘记换行。多数题对行末换行不敏感,但有些题严格比对,养成加 "\n" 的习惯。
多打空格。行末多一个空格,严格评测(如 NOIP)会判 WA。
把上面的完整代码不看页面敲一遍,提交到 P1001。
然后把输入改成 1000000000 1000000000,看输出是否为 2000000000。
如果输出是负数,说明你把变量改成了 short —— 亲手体验一次溢出。
int 占 4 字节 = 32 位。其中 1 位是符号位,剩下 31 位表示大小。
最大值 = 2³¹ − 1 = 2147483647 ≈ 2.14×10⁹。最小值 = −2³¹ = −2147483648。
| 类型 | 字节 | 范围 | 十进制位数 |
|---|---|---|---|
| int | 4 | ±2.14×10⁹ | 10 位 |
| long long | 8 | ±9.22×10¹⁸ | 19 位 |
| unsigned long long | 8 | 0 ~ 1.84×10¹⁹ | 20 位 |
记住“19”这个数:long long 最多表示 19 位十进制整数。超过 19 位就必须用高精度(字符串/数组模拟)。
推论:只要题目里出现“求和”“相乘”,先用草稿纸估一下最坏情况是多少,超过 2×10⁹ 立刻换 long long。
int 换成 double 读入 1 2,输出会变成什么样?为什么会多出小数?cin >> x 循环 10 次能正确读入吗?为什么?endl 会比 "\n" 慢?慢在哪一步?小鱼从 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 | 余数就是不足一小时的分钟数。 |
<< " " << | 两个数之间用一个空格隔开,行末只换行不加空格。 |