对于目前还有哪些字母可以选择, 可以当作 贪心的在原字符串中找到我们已选择的子序列,然后从这个贪心的结果的末尾截断,原字符串剩下的右边部分就是我们还能选择的字符串,那么,我们的操作就可以转化为,在剩下的字符串中选择一个字符,然后在这个字符第一次出现的位置开始截断,如果我们能截断整个字符串,那就能赢;
对于当前的字符串先手能否胜利,可以看先手能选择哪些索引,如果某个索引选择后剩下的字符串是先手必败,那么这个选择这个索引对应的字符就能让原字符串胜利,如果每个可选择的索引,剩下的都是必胜态,那么当前字符串就是必败态;
所以我们可以考虑从字符串的末尾开始往前枚举 , 维护每个字符第一次出现的索引位置,以及当前可选择的索引中,必败态的数量,如果大于零当前就是必胜态,否则就是必败态
#include <bits/stdc++.h>
using namespace std;
#define print(x) cout<<#x<<": ";for(auto _:x)cout<<_<<' ';cout<<endl;
#define dbg(x) cout<<#x<<": "<<(x)<<endl;
int main() {
string s;
cin >> s;
s = "!" + s;
int n = s.size() - 1;
vector<int> suf(26);
vector<int> f(n + 2, -1);
f[n + 1] = 0;
f[n] = 1;
suf[s[n] - 'a'] = n;
int zero_cnt = 1;
for (int i = n - 1; i >= 1; i--) {
int ele = suf[s[i] - 'a'];
if (ele != -1 && f[ele + 1] == 0) {
zero_cnt--;
}
suf[s[i] - 'a'] = i;
if (zero_cnt)f[i] = 1;
else f[i] = 0;
if (!f[i])zero_cnt++;
}
if (f[1])cout << "kou" << endl;
else cout << "yukari" << endl;
return 0;
}
// 64 位输出请用 printf("%lld")

京公网安备 11010502036488号