AtCoder ABC380D - Strange Mirroring 简单分治
题目链接:https://atcoder.jp/contests/abc380/tasks/abc380_d
题目大意:
给定一个字符串 \(S\),该字符串由大写和小写英文字母组成。
我们对 \(S\) 执行 \(10^{100}\) 次以下操作:
- 首先,通过将 \(S\) 中的大写字母转换为小写字母,将小写字母转换为大写字母,创建一个字符串 \(T\)。
- 然后,按照此顺序连接 \(S\) 和 \(T\) 形成一个新的 \(S\)。
接下来有 \(Q\) 次询问。第 \(i\) 次查询给你一个整数 \(K_i\),你需要回答出:
- 在所有操作(即上述的对字符串 \(S\) 执行的 \(10^{100}\) 次操作)完成后,字符串 \(S\) 从前往后的第 \(K_i\) 个字符是啥?
解题思路:
定义一个变量 \(c\) 表示当前反转的次数 \(\text{ mod } 2\) 的结果。
设 \(n\) 为 \(S\) 能够得到的最短的 \(\gt K_i\) 的字符串。
若 \(K_i \gt n/2\),则将问题缩小一半后,K_i -= n/2; c ^= 1。
最后,根据 \(c\) 的值确定是否对字符串进行大小写转换。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
char s[maxn];
int n, q;
int main() {
scanf("%s%d", s+1, &q);
n = strlen(s+1);
while (q--) {
int c = 0;
long long m = n, k;
scanf("%lld", &k);
while (m < k) m <<= 1;
while (m != n) {
if (k > m/2) {
k -= m/2;
c ^= 1;
}
m >>= 1;
}
if (!c) printf("%c ", s[k]);
else printf("%c ", islower(s[k]) ? toupper(s[k]) : tolower(s[k]));
}
return 0;
}
浙公网安备 33010602011771号