ABC258C 题解
题面
AT_abc258_c [ABC258C] Rotation
题目描述
给定正整数 \(N,Q\),以及一个长度为 \(N\) 的由小写英文字母组成的字符串 \(S\)。
请处理 \(Q\) 个如下所述的查询。查询有以下两种类型之一:
1 x:将 \(S\) 的末尾字符删除,并插入到开头,连续执行 \(x\) 次。2 x:输出 \(S\) 的第 \(x\) 个字符。
输入格式
输入以如下格式从标准输入给出。
\(N\) \(Q\) \(S\) \(\mathrm{query}_1\) \(\mathrm{query}_2\) \(\vdots\) \(\mathrm{query}_Q\)
每个查询的格式如下,其中 \(t\) 为 \(1\) 或 \(2\)。
\(t\) \(x\)
输出格式
对于每个 2 x 类型的查询,输出答案,每个答案占一行。
输入输出样例 #1
输入 #1
3 3
abc
2 2
1 1
2 2
输出 #1
b
a
输入输出样例 #2
输入 #2
10 8
dsuccxulnl
2 4
2 7
1 2
2 7
1 1
1 2
1 3
2 5
输出 #2
c
u
c
u
说明/提示
数据范围
- \(2 \leq N \leq 5 \times 10^5\)
- \(1 \leq Q \leq 5 \times 10^5\)
- \(1 \leq x \leq N\)
- \(|S| = N\)
- \(S\) 由小写英文字母组成。
- 至少有一个
2 x类型的查询。 - \(N,Q,x\) 均为整数。
样例解释 1
第 \(1\) 个查询时,\(S\) 为 abc,因此输出第 \(2\) 个字符 b。第 \(2\) 个查询时,\(S\) 由 abc 变为 cab。第 \(3\) 个查询时,\(S\) 为 cab,因此输出第 \(2\) 个字符 a。
由 ChatGPT 4.1 翻译
这是一道橙题,但是我没有自己做出它,我依稀记得有一个公式可以快速的解决它的一部分,确实是这样,后面会讲到他。
这题核心在于一个发现:
假设有字符串abc,模拟一下op == 1的过程,每次移动一个。
abc a是起点。
cab a左边的c变成了起点。
bca c左边的b又边成了起点。
(均为循环移位)
发现了吗,每一次op == 1的操作不过,只是在将起点循环左移!
公式自然显而易见,会在代码里。
用于解决一个起点b右边p的单位的下标(p可能大于总长n,因为循环移位,例如p = 6时在末位,p = 7时则在首位)的公式:
(b + p - 1) % n + 1
蒙了半天才蒙到的
对比(b + p) % n:
(b + p - 1) % n + 1:取值范围1 ~ n。
(b + p) % n:取值范围0 ~ n - 1。
#include <bits/stdc++.h>
using namespace std;
signed main() {
int n, T;
cin >> n >> T;
string s;
cin >> s;
s = '!' + s;
int b = 0;
while (T--) {
int op;
cin >> op;
if (op == 1) {
int y;
cin >> y;
y %= n;
b = (b - y + n) % n; // 取模当心负数!
} else {
int p;
cin >> p;
cout << s[(b + p - 1) % n + 1] << '\n'; // 讲过了
}
}
return 0;
}
误区警示!
写题解的时候才发现。
b = 0是合法的,b的取值范围是[0, n - 1],p才是[1, n],毕竟这个字符串默认第一个字符的下标为1!
p是第一个字符,不是后一个字符。
上面的讲述只是一种好的思考方式(当然,也是正确的,但是和代码的思路有所不同)。
在代码里b是一个向右的有效偏移量,起点的下标怎么可能是0呢?
如果b = 0就是说明,当前字符串经过多次操作后,新字符串和读入的字符串是一样的。
换一种思路,b也可以理解为通过\(O(1)\)的操作代替了\(O(n)\)的改变每个字符的下标!(例如b = 1代表全体+1,原n变1)。
总结
1.如果发现某题好像可以用某个模板解决一定不要急于套模板。
2.还是这句话,不审清题,不开始下一步执行,从现在开始无论难度至少读两次题
3.代码AC不代表真的理解了,所以复盘是绝对正确,且不浪费时间的。
4.取模当心负数。

浙公网安备 33010602011771号