Codeforces 71A:Way Too Long Words 错误复盘
题目并不难,错误主要集中在输入协议和输出边界:漏读第一行的 n、把一个单词放进多余的长度循环、把 > 10 写成了错误的边界判断,以及没有为每个单词输出换行。
题目要求
第一行输入一个整数 n,表示后面有多少个单词;接下来输入 n 个单词。
- 单词长度 大于 10 时,缩写为:首字符 + 中间字符数量 + 尾字符。
- 单词长度 小于等于 10 时,原样输出。
- 每个单词占一行。
例如:
localization
长度为 12,缩写为:
l10n
10 是中间字符的数量,不是单词总长度减去首尾字符后的文字内容。
四个错误及修正
1. 漏读第一行的 n
题目第一行先给出单词总数。如果不读取 n,程序就无法准确知道什么时候停止,也容易把测试数据或下一组输入误当成单词。
正确的输入骨架是:
int n;
cin >> n;
while (n--)
{
string word;
cin >> word;
// 处理一个单词
}
这里的循环次数由题目输入决定,而不是由某个单词的长度决定。
2. 多余的长度循环导致重复输出
错误思路类似:
for (int i = 0; i < count; i++)
{
cout << word;
}
如果 count 是单词长度,那么一个 4 位单词会被输出 4 次。题目要求的是“每个单词处理一次”,因此外层只需要遍历 n 个单词,单词内部不需要再按长度重复输出。
正确的结构是:
读取一个单词
↓
判断长度
↓
输出一次结果
↓
换行
3. 边界必须是严格大于 10
题目要求:只有长度 > 10 的单词才缩写。
if (word.size() > 10)
{
// 缩写
}
else
{
// 原样输出
}
长度为 10 的单词必须原样输出,因此不能写成 >= 10。这类边界条件要特别用长度为 10 和长度为 11 的样例检查。
4. 每个单词后都要换行
输出完一个单词后立即写入换行:
cout << result << '\n';
也可以使用 endl,但竞赛代码中通常使用 \n,避免不必要的刷新:
cout << result << endl;
如果忘记换行,多个答案会连在同一行,即使缩写逻辑正确,也会被判错。
正确的 C++ 实现
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
while (n--)
{
string word;
cin >> word;
if (word.size() > 10)
{
cout << word.front() << word.size() - 2 << word.back();
}
else
{
cout << word;
}
cout << '\n';
}
return 0;
}
为什么 word.size() - 2 是安全的?
它只在 word.size() > 10 的分支中执行,所以单词长度至少为 11,不会发生无符号整数下溢。首字符和尾字符分别用 front() 与 back() 取得,中间字符数量就是总长度减去 2。
最小测试集
输入:
4
word
localization
internationalization
abcdefghij
输出:
word
l10n
i18n
abcdefghij
重点检查:
| 测试 | 预期行为 |
|---|---|
| 长度小于 10 | 原样输出 |
| 长度等于 10 | 原样输出,验证不能写成 >= 10 |
| 长度大于 10 | 输出首字符、长度 - 2、尾字符 |
| 多个单词 | 每个单词只输出一次,并且各占一行 |
提交前检查清单
- 是否读取了第一行的
n? - 是否恰好循环
n次? - 是否只对每个单词处理一次?
- 判断条件是否为
word.size() > 10? - 是否输出了
word.front()、word.size() - 2和word.back()? - 每个单词后是否都有
\n? - 是否用长度 10、长度 11 和多个单词进行过测试?
这道题留下的经验
这次错误不是算法复杂度问题,而是“输入数量、循环对象、边界条件、输出格式”没有逐项对齐题面。以后遇到简单题,也应先把题目拆成四个问题:
输入有几组?
每组数据处理几次?
边界条件是什么?
输出格式是否逐项匹配?
把这四项确认完,再写核心判断,通常比直接套循环更不容易出错。