題意:有一個長為n的01串,兩個人輪流操作,每個人可以把某個長度為m的區間變成相同顏色,誰在操作后整個串顏色相同就贏了。問最后是誰贏?(有可能平局)
思路:容易發現,如果第一個人不能一擊必勝,那么他就會向平局發展。同理,如果第二個人不能在第一個人的所有第一步的可能走法之后都能一擊必勝,那么他也會向平局發展。所有,問題轉化為了第一個人能不能一擊必勝,第二個人能不能在第一步的所有走法之后一擊必勝。
先考慮第一個人,我們只要判斷能不能找到一個區間,使得這個區間的顏色相同之后,向左右延伸可以到串的兩端即可。設當前枚舉的區間是[l, r],如果s[l - 1]和s[r + 1]顏色相同,並且s[l - 1]向左延伸可以到1,s[r + 1]向右延伸可以到n,那么就找到了一個必勝區間。
現在考慮對於每個第一步,第二個人能不能必勝。還是假設第一步覆蓋的區間是[l, r],那么如果l - 1和r + 1有一個不能延伸到端點,第二個人就不可能必勝(l = 1和r = n的情況除外)。如果都可以延伸到兩端,那么s[l - 1]和s[r + 1]一定不同。那么只有1到l - 1和 r + 1到n都小於等於m才行,即無論你選什么顏色,我都可以把剩下的顏色不一樣的部分變成一樣的,這樣必勝情況 + 1。l = 1和r = n的情況同理,特判一下即可。最后,看一下第一步方案數和必勝數是否一樣即可。
代碼:
#include <bits/stdc++.h> using namespace std; const int maxn = 100010; char s[maxn]; int l[maxn], r[maxn]; int n, m; int main() { scanf("%d%d", &n, &m); scanf("%s", s + 1); l[0] = 1; for (int i = 1; i <= n; i++) { if(s[i] == s[i - 1]) l[i] = l[i - 1]; else l[i] = i; } r[n + 1] = n; for (int i = n; i >= 1; i--) { if(s[i] == s[i + 1]) r[i] = r[i + 1]; else r[i] = i; } if(r[1] == n) { printf("tokitsukaze\n"); return 0; } int cnt = 0; for (int l1 = 1, r1 = m; r1 <= n; l1++, r1++) { if(l[l1 - 1] == 1 && r[r1 + 1] == n) { if(l1 == 1 || r1 == n || (s[l1 - 1] == s[r1 + 1])) { printf("tokitsukaze\n"); return 0; } else { if(l1 - 1 <= m && n - r1 <= m) cnt++; } } else if(l1 == 1) { if(n - r1 <= m) cnt++; } else if(r1 == n) { if(l1 - 1 <= m) cnt++; } } if(cnt == n - m + 1) printf("quailty\n"); else printf("once again\n"); }