题意:
给你一个串,只包含".“和"X”,你可以将连续的a个".“变成"X”,你的对手则是b个(a>b),你先手,问你最终是否能赢。
题解:
这种博弈的题目我是真不会。。
首先,如果两个".“之间有"X”,那么这两段是不会相互影响的,所以可以一段一段的去考虑。对于长度<b的段我们不用管它,剩余情况分成3类:
1.b<=len<a
2.a<=len<2b
3.2b<=len
如果其中有一个情况1,那么b必胜,因为b在无路可走的情况下可以拿这一段,同时因为a>b,在这时候a一定没有下一步可以走。那么,如果在a拿完第一次的时候,还有情况3,那么b就可以构造一个长度为b的串。也就是当情况3有两种及以上的时候,b必胜。
接下来是情况3只有1种的时候,为了让a赢,如果情况2有奇数个,那么就是说情况3的长度只能让a拿两次,并且b不能再拿。(因为第一次a必须拿这个串,否则就存在长度>=2*b的了)
如果是2的个数有偶数个,那么a可以拿一次并且剩下两个长度<b的串,或者将其从中间分开,分成两个情况2.
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
char s[N];
int a,b;
int check(){
int num[4]={0};
int len=strlen(s);
int cnt=0,mx=0;
for(int i=0;i<len;i++){
if(s[i]=='.')
cnt++;
else{
mx=max(mx,cnt);
num[1]+=(cnt>=b&&cnt<a);
num[2]+=(cnt>=a&&cnt<2*b);
num[3]+=(cnt>=2*b);
cnt=0;
}
}
mx=max(mx,cnt);
num[1]+=(cnt>=b&&cnt<a);
num[2]+=(cnt>=a&&cnt<2*b);
num[3]+=(cnt>=2*b);
if(num[1]||num[3]>=2)
return 0;
if(!num[3]&&num[2]%2)
return 1;
if(!num[3]&&!(num[2]%2))
return 0;
if(num[2]%2&&mx>=2*a&&mx<=a+3*b-2)
return 1;
if(!(num[2]%2)&&((mx>=a&&mx<=a+2*b-2)||(mx>=3*a&&mx<=a+4*b-2)))
return 1;
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&a,&b);
scanf("%s",s);
printf("%s\n",check()?"YES":"NO");
}
return 0;
}