链接
http://codeforces.com/contest/1221/problem/E
题意
给定一个只包含’.‘和’X’的字符串,两个人轮流对字符串进行操作。先手方选择一段连续的a个’.’,将其变成’X’,后手方选择一段连续的b个’.’,将其变成’X’。无法操作的人输掉游戏,问先手方是否存在必胜策略。
a>=b,n<=300000
分析
先处理出所有连续的’.'子串,可以得到这样一些性质:
如果出现了一个长度为[0,b-1]之间的子串,那么这个子串是没用的。
如果出现了一个长度为[b,a-1]之间的子串,那么后手方必胜。
如果出现了一个长度为[a,2b-1]之间的子串,那么无论谁取,这个子串都为变为[0,b-1]的子串。
接下来考虑长度大于等于2b的子串。
如果有两个及以上这样的子串,那么后手方一定能弄出一个[b,a-1]的子串,于是后手方必胜。
如果没有这样的子串,那么需要讨论[a,2b-1]子串数量的奇偶性。
如果只有一个这样的子串,则需讨论[a,2b-1]子串数的奇偶性和这个子串的长度:
若为奇数,先手方想要胜利,必须将子串拆分为a+[0,b-1]+[a,2b-1],因此子串的长度必须在[2a,a+3b-2]之间。
若为偶数,先手方想要胜利,必须将子串拆分为a+[a,2b-1]+[a,2b-1]或者a+[0,b-1]+[0,b-1],因此子串的长度必须在[a,a+2b-2]和[3a,a+4b-2]之间。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
template<class T>inline void MAX(T &x,T y){if(y>x)x=y;}
template<class T>inline void MIN(T &x,T y){if(y<x)x=y;}
template<class T>inline void rd(T &x){
x=0;char o,f=1;
while(o=getchar(),o<48)if(o==45)f=-f;
do x=(x<<3)+(x<<1)+(o^48);
while(o=getchar(),o>47);
x*=f;
}
const int M=3e5+5;
int cas,n,a,b,A[M];
char str[M];
int main(){
#ifndef ONLINE_JUDGE
freopen("jiedai.in","r",stdin);
// freopen("jiedai.out","w",stdout);
#endif
rd(cas);
while(cas--){
rd(a),rd(b);
scanf("%s",str+1);
int n=strlen(str+1);
str[n+1]='X';
int cnt1=0,cnt2=0,cnt3=0,len,tmp=0;
for(int i=1;i<=n+1;i++){
if(str[i]=='.')tmp++;
else{
if(tmp>=b&&tmp<a)cnt1++;
if(tmp>=a&&tmp<b+b)cnt2++;
if(tmp>=b+b)cnt3++,len=tmp;
tmp=0;
}
}
if(cnt3>=2||cnt1)puts("NO");
else if(cnt3==0)puts(cnt2%2?"YES":"NO");
else if(cnt2%2)puts(len>=2*a&&len<=a+3*b-2?"YES":"NO");
else puts((len>=a&&len<=a+2*b-2||len>=3*a&&len<=a+4*b-2)?"YES":"NO");
}
return (0-0);
}