Game With String [思维题]

链接

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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值