Solution - Codeforces 1190C Tokitsukaze and Duel
考虑到两人对应的操作是相同的,于是可以从对称的角度来思考。
考虑到在先手做出操作后,后手一个较为特殊的操作是不做任何影响,也就是重复先手的操作。
能够发现如果对于后手这不能必胜,那么他一定不会去产生影响,并又把这个局面留给先手,相当于是先后手的交换。
对于先手又是同样的,因为两人操作相同,对于他也是不必胜的,那么他也会重复操作留给后手,那么就平局了。
于是能够知道的是,如果初始状态就能必胜,那么先手必胜。
否则如果无论先手怎样操作,后手都能必胜的话,后手必胜。
否则就是先手存在一种方式,使得操作后后手不能必胜,那么两人就会一直重复第一次的操作,最终平局。
对于判断,可以提前预处理好前缀同色段的长度与后缀连续段的长度。
那么对于先手,其选择了段 \([l, r]\),那么他就只关心 \([1, l], [r, n]\) 是否同色。
对于后手,先手选择了段 \([l, r]\) 涂成了颜色 \(c\),那么只有当 \([1, l], [r, n]\) 只有一边需要重新涂色且最远颜色距离 \(\le k\) 即可。
时间复杂度 \(\mathcal{O}(n)\)。
#include<bits/stdc++.h>
constexpr int maxn = 1e5 + 10;
int n, k;
char s[maxn];
bool f[maxn], g[maxn];
int fmn[maxn][2], fmx[maxn][2], gmn[maxn][2], gmx[maxn][2];
int main() {
scanf("%d%d%s", &n, &k, s + 1);
f[0] = true;
for (int i = 1; i <= n; i++) {
f[i] = f[i - 1] && (s[i] == s[1]);
}
g[n + 1] = true;
for (int i = n; i; i--) {
g[i] = g[i + 1] && (s[i] == s[n]);
}
if (f[n - k] || g[k + 1]) {
return puts("tokitsukaze"), 0;
}
for (int l = 1, r = k; r <= n; l++, r++) {
if (f[l - 1] && g[r + 1] && s[1] == s[n]) {
return puts("tokitsukaze"), 0;
}
}
fmn[0][0] = fmn[0][1] = n + 1;
for (int i = 1; i <= n; i++) {
for (int op : {0, 1}) {
fmn[i][op] = fmn[i - 1][op], fmx[i][op] = fmx[i - 1][op];
}
fmn[i][s[i] - '0'] = std::max(fmn[i][s[i] - '0'], i);
fmx[i][s[i] - '0'] = i;
}
gmx[n + 1][0] = gmx[n + 1][1] = 0;
for (int i = n; i; i--) {
for (int op : {0, 1}) {
gmn[i][op] = fmn[i + 1][op], gmx[i][op] = gmx[i + 1][op];
}
gmx[i][s[i] - '0'] = std::max(gmx[i][s[i] - '0'], i);
gmn[i][s[i] - '0'] = i;
}
bool fl = true;
for (int l = 1, r = k; r <= n; l++, r++) {
for (char c : {'0', '1'}) {
bool gl = l > 1 && (! f[l - 1] || c != s[1]);
bool gr = r < n && (! g[r + 1] || c != s[n]);
if ((gl && gr) || (gl && fmx[l - 1][c ^ '1'] - fmn[l - 1][c ^ '1'] + 1 > k) ||
(gr && gmx[r + 1][c ^ '1'] - gmn[r + 1][c ^ '1'] + 1 > k)) {
fl = false;
break;
}
}
}
puts(fl ? "quailty" : "once again");
return 0;
}