首先分析A能获胜的情况 A能获胜 当且仅当A拿完后所有剩下的都<b
所以一旦存在一个大小为X的 且 b<=X<a 则必是后手赢
当X为 a<=x<2*b 的时候 无论A或B拿 两个人都只能拿一次 拿完就<b作废
而X>=2*b时 如果是B先手 则B可以构造出一个大小刚好为b的来赢得胜利 所以如果有两个及以上的X>=2*b 后手必胜
当有且仅有一个X>=2*b时 A肯定要先操作这块来获得胜利 A能获胜 当且仅当 A拿完后的块只能在[1,b)和[a,2*b)这个范围内
因为一旦出现[b,a)或者[2*b,无穷)这两个范围内的块 A必输 所以我们只要暴力枚举 看是否存在A取完后 [a,2*b) 范围内的块为偶数的情况即可
#include<bits/stdc++.h> #define RG register using namespace std; typedef long long ll; const int MAXN = 500005; char f[300005]; int num[300005]; int number[300005]; int cnt = 0; int aa, bb, cc; int main() { int T; int a, b, aim; scanf("%d", &T); while (T--) { aim = cnt = 0; scanf("%d %d", &a, &b); scanf("%s", f + 1); int len = strlen(f + 1); for (int i = 1; i <= len + 1; i++) { num[i] = 0; } for (int i = 1; i <= len; i++) { num[i] = f[i] == '.' ? (num[i - 1] + 1) : 0; } for (int i = 1; i <= len + 1; i++) if (num[i] == 0 && num[i - 1] > -0) { number[++cnt] = num[i - 1]; } bool flag = 1; int now = 0; for (int i = 1; i <= cnt; i++) { if (number[i] >= b && number[i] < a) { flag = 0; break; } if (number[i] >= 2 * b) { if (aim == 0) { aim = i; } else { flag = 0; break; } } if (number[i] >= a && number[i] < 2 * b) { now++; } } if (flag == 0) { printf("NO\n"); } else { if (aim == 0) { if (now & 1) { printf("YES\n"); } else { printf("NO\n"); } } else { //cout<<" aim: "<<aim<<endl; bool flag2 = 0; int sum = number[aim]; for (int r1 = 0; sum - a - r1 >= 0; r1++) { int r2 = sum - a - r1; if (r1 >= 2 * b || (r1 >= b && r1 < a)) { continue; } if (r2 >= 2 * b || (r2 >= b && r2 < a)) { continue; } int add = 0; if (r1 >= a && r1 < 2 * b) { add++; } if (r2 >= a && r2 < 2 * b) { add++; } if ((now + add) % 2 == 0) { flag2 = 1; break; } } if (flag2) { printf("YES\n"); } else { printf("NO\n"); } } } } return 0; }