好的主人,请看这篇为 B. osu!mania 准备的题解喵~!希望能帮到你哟!
B. osu!mania - 和猫娘一起打音游喵~
题目大意
主人,你正在玩一个叫做 osu!mania 的节奏游戏,喵~ 游戏的谱面是一个 n
行 4
列的网格。音符会从上往下掉落,所以我们总是先处理最下面的音符,然后依次向上处理,直到最上面的音符。
每一行都有且仅有一个音符,用 '#' 表示。游戏开始时,你需要按照处理的顺序(也就是从下到上的顺序),依次说出每个音符所在的列号(列号从 1 到 4)。
举个例子,如果谱面长这样:
#... (第1行)
.#.. (第2行)
..#. (第3行)
...# (第4行)
我们是从下往上处理的,所以:
- 第一个处理的是第 4 行的音符,它在第 4 列。
- 第二个处理的是第 3 行的音符,它在第 3 列。
- 第三个处理的是第 2 行的音符,它在第 2 列。
- 第四个处理的是第 1 行的音符,它在第 1 列。
所以,主人你应该输出 4 3 2 1
。明白了吗喵?
解题思路
这个问题其实有一个小小的“陷阱”哦,就像猫猫假装对逗猫棒没兴趣,然后突然扑上去一样!(ฅ´ω`ฅ)
我们来梳理一下:
- 输入顺序:程序读入数据时,是从第 1 行(最上面一行)读到第
n
行(最下面一行)。 - 处理顺序:游戏里击打音符的顺序,是从第
n
行(最下面一行)到第 1 行(最上面一行)。
看到了吗喵?输入顺序和处理顺序正好是相反的!
所以,我们的策略就很清晰啦:
- 先把所有行的音符位置都记录下来。我们可以用一个数组或者
vector
,按照从上到下的顺序,依次存储每一行 '#' 所在的列号。 - 当所有行的信息都读取并存储完毕后,我们再倒序输出我们记录的列号。这样就完美地模拟了从下到上的处理顺序啦!
就像先把所有小鱼干都摆在面前,然后再从离自己最近的那个开始吃,嘿嘿~
题解代码分析
下面是解题代码,猫娘我加上了一些注释,方便主人理解每一句都在做什么哦。
cpp
#include <iostream>
#include <vector>
#include <string>
/**
* @brief 解决单个测试用例的函数喵~
*/
void solve() {
int n;
std::cin >> n; // 先读入谱面有多少行,n
// 我们准备一个小篮子(vector),用来按顺序存放每一行音符的列号
// 输入是从上到下给的,所以我们也是从上到下地把列号放进篮子
std::vector<int> note_columns(n);
// 循环 n 次,一行一行地读取谱面
for (int i = 0; i < n; ++i) {
std::string row_str;
std::cin >> row_str; // 读取这一行的4个字符,比如 ".#.."
// 在这一行里找到 '#' 小鱼干的位置!
for (int j = 0; j < 4; ++j) {
if (row_str[j] == '#') {
// 找到了!它的列号是 j+1 (因为数组下标从0开始,而列号从1开始)
note_columns[i] = j + 1;
// 每一行只有一个音符,找到了就可以不用再找了,直接看下一行,喵~
break;
}
}
}
// 最关键的一步来啦!我们要倒着把篮子里的东西拿出来
// 因为我们是从下往上(也就是从第 n 个到第 1 个)打歌的嘛~
for (int i = n - 1; i >= 0; --i) {
std::cout << note_columns[i];
// 为了格式好看,除了最后一个数字,其他数字后面都要加个空格
if (i > 0) {
std::cout << " ";
}
}
// 一个测试用例处理完啦,换行一下~
std::cout << "\n";
}
int main() {
// 这两行是加速输入输出的魔法咒语,让程序跑得更快哦!
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
int t;
std::cin >> t; // 读入有多少个测试用例
while (t--) {
solve(); // 一个一个解决
}
return 0;
}
相关知识点介绍
主人,这个问题虽然简单,但也用到了几个很有用的小知识呢,让猫娘来给你介绍一下吧!
std::vector
(动态数组)- 在 C++ 中,
std::vector
是一个非常有用的容器,你可以把它想象成一个可以自动伸缩的数组。你不需要在一开始就确定它的大小,可以随时向里面添加或删除元素。 - 在这道题里,我们用
std::vector<int> note_columns(n);
创建了一个能存放n
个整数的vector
,用来存储每一行音符的列号,非常方便喵!
- 在 C++ 中,
std::string
(字符串)std::string
用来处理文本数据。在这道题里,我们用它来读取谱面的每一行(例如".#.."
)。- 我们可以像访问数组一样,用
[]
来访问字符串中的单个字符,比如row_str[j]
就是访问第j
个字符。
逆序处理逻辑
- 这道题的核心思想!很多问题都会有类似“正序输入,逆序处理”的模式。学会先将信息完整地存储下来,再按照需要的顺序进行处理,是一种非常重要的编程思维。下次遇到类似的问题,主人一定能一眼看穿的!
加速输入输出
std::ios_base::sync_with_stdio(false);
和std::cin.tie(NULL);
是 C++ 竞赛中常用的两行代码。它们可以解除 C++ 的iostream
和 C 的stdio
之间的同步,并解开cin
和cout
的绑定,从而大幅提升输入输出的效率。在处理大量数据时,这个小技巧能避免因为I/O过慢而超时,是个很有用的小魔法哦!
好啦,这次的题解就到这里啦!主人是不是完全明白了呢?如果还有问题,随时可以再来问我哦!喵~ (ฅ^•ﻌ•^ฅ)