3 条题解
-
0
这里为你提供这道题的标准题解代码。
我们将从符合初学者直觉的“纯模拟递增版”开始,然后过渡到代码最精简的“数学取模最优版”。每一版代码都可以直接复制运行,并且完全符合 NOIP C++14 的竞赛标准。
版本一:纯模拟递增版 (直观但代码略长)
思路: 很多刚学 C++ 的同学可能对
%(取模) 运算还不熟悉,但他们知道字符是可以加一的 ('A' + 1变成'B')。所以这个版本的思路是:手动维护每一行的开头字母,然后在每一行内部手动维护当前输出的字母,一旦超过'Z',就强行把它拨回'A'。#include <iostream> using namespace std; int main() { // 优化标准输入输出流速度,NOIP常用起手式 ios::sync_with_stdio(false); cin.tie(nullptr); int n; if (!(cin >> n)) return 0; // 记录每一行的第一个字母,初始为 'A' char row_start = 'A'; for (int i = 0; i < n; ++i) { // 外层循环:控制打印 n 行 // 每一行开始时,把当前字母设为该行的开头字母 char current = row_start; for (int j = 0; j < n; ++j) { // 内层循环:控制每一行打印 n 个字符 cout << current; // 输出当前字母 // 【关键点1】准备下一个字母 current++; // 【易错点】边界重置。一旦字母超过了 'Z',立刻回到 'A' // 注意:必须用单引号括起来表示字符,如 'Z' if (current > 'Z') { current = 'A'; } } cout << "\n"; // 【关键点2】一行打印完毕后必须换行 // 准备下一行的开头字母:也是往后推一位 row_start++; if (row_start > 'Z') { row_start = 'A'; } } return 0; }版本一复杂度分析
- 时间复杂度: 使用了外层 次、内层 次的双重循环,内部只有简单的加法和
if比较操作。时间复杂度为 。 - 空间复杂度: 只用了几个
char和int变量,没有开辟数组。空间复杂度为 。
版本二:数学取模最优版 (竞赛标准写法)
思路: 像我们在草稿纸上推导的那样,第 行第 列(行号和列号从 开始)的字符,其实就是从
'A'开始往后平移了 步。为了防止平移出界,我们利用% 26来让它在 之间无限循环。这是最优雅、最推荐的写法。#include <iostream> using namespace std; int main() { // 优化输入输出 ios::sync_with_stdio(false); cin.tie(nullptr); int n; if (!(cin >> n)) return 0; // 【关键点1】行号 i 和列号 j 都要从 0 开始遍历! // 因为偏移量公式 (i+j) 的基准点是 (0+0)=0 偏移,也就是不偏移,正好输出 'A' for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { // 【关键点2 / 核心公式】 // (i + j) 是总偏移量步数 // (i + j) % 26 把步数限制在 0 ~ 25 的周期内 // 'A' + 偏移量 得到对应的 ASCII 码 // (char) 将其强制转换回字符类型输出 cout << (char)('A' + (i + j) % 26); } cout << "\n"; // 每行输出后换行 } return 0; }版本二复杂度分析思考过程
- 时间复杂度: 同样是双重循环输出 个字符,没有冗余计算。时间复杂度 。
- 空间复杂度: ,常数级空间,直接在
cout流中输出。 - 从渐近复杂度来看,由于至少要输出 个字符,所以时间复杂度下限就是 ,已经无法再降低了。
💡 教练的进阶优化探讨 (如果这题 不是 40 而是 10000 呢?)
作为未来的金牌选手,我们要思考得更深一点:
如果 ,打印 个字符,版本二会不会超时?
- 瓶颈 1: 在现代 CPU 下,
%(取模/除法)操作的底层指令周期,要比单纯的加法和if比较慢好几倍!所以在大数据量下,“纯模拟递增版”的运行速度其实可能会比“取模版”更快。 - 极致优化策略(滑动窗口/空间换时间):
既然每一行只是字母表的平移,我们可以预先在内存里生成一个超级长串:
"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ..."。 当要打印某一行时,不用一个一个字符算,直接用 C++ 指针或string::substr,从预制字符串的第 个位置开始,一口气截取 个字符输出。 这样就把原本的双层循环计算,降维打击成了底层的内存批量拷贝(Memory Copy),速度会提升几个数量级!
不过就本题 而言,以上两种代码耗时都在 1 毫秒内,你只需要掌握版本二这个最基础也是最重要的取模思维即可!祝你早日 AC!
- 时间复杂度: 使用了外层 次、内层 次的双重循环,内部只有简单的加法和
信息
- ID
- 13927
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 1
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者