[codeforces1221E]-Game With String-博弈

说在前面

把题读错了。。。
对自己感到无语TvT


题目

codeforces1221E传送门

题目大意

Alice和Bob在玩游戏
现在给出一个字符串,其中含有’X’和’.’(不带引号)
每次操作,Alice可以把A个连续的’.‘变成’X’,Bob可以把B个连续的’.‘变成’X’(保证A>B),谁走不动谁输
如果双方采取最优策略,问最后Alice是否能赢

多组数据,字符串总长度 ≤ 3 × 1 0 5 \leq 3\times 10^5 3×105


解法

首先Alice和Bob的操作是不同的,因此不是组合游戏,不能用SG那一套理论,需要从寻找必胜态入手

(然后没想出来,看了题解发现我题读错了)

我们取出序列中连续的" . . .",将其长度记为len
并约定:
l e n < B lenlen<B 为1类串
B ≤ l e n < A B\leq lenBlen<A 为2类串
A ≤ l e n < 2 × B A\leq len<2\times B Alen<2×B 为3类串
2 × B ≤ l e n 2\times B \leq len 2×Blen 为4类串

不难发现,如果序列中出现一个2类串,那么Alice必定输(因为A>B,如果Alice走不动了,Bob至少还能走一步2类串)。进一步的,如果有两个及以上的4类串,Bob一定能够造出一个2类串,Alice必输。

如果没有4类串,那么输赢由3类串个数的奇偶决定

如果恰好只有一个4类串,Alice的先手就需要保证她能赢,所以判断一下这个4类串在被Alice操作一次之后,能否出现先手必输的局面,这个根据3类串的奇偶以及4类串的长度特判就行了


下面是代码

#include 
#include 
#include 
using namespace std ;

// A > B
int T , A , B , B2 , sta[300005] , topp , slen ;
char ss[300005] ;

void preWork(){
	topp = 0 ;
	slen = strlen( ss + 1 ) , B2 = B * 2 ;

	int L = 1 , R ;
	while( L <= slen ){
		while( ss[L] == 'X' ) L ++ ;
		R = L ;
		while( ss[R] == '.' ) R ++ ;
		if( R - L >= B ) sta[++topp] = R - L ;
		L = R ;
	} sort( sta + 1 , sta + topp + 1 ) ;
}

bool cut_1_or_3( int len ){
	if( len <= A + 2 * B - 2 ) return true ;
	if( A * 3 <= len && len <= A + B2 * 2 - 2 ) return true ;
	return false ;
}

bool cut_1_and_3( int len ){
	if( A + A <= len && len <= B - 1 + A + B2 - 1 ) return true ;
	return false ;
}

void solve(){
	int cnt2 = 0 , cnt3 = 0 , cnt4 = 0 ;
	for( int i = 1 ; i <= topp ; i ++ ){
		if(                sta[i] < A  ) cnt2 ++ ;
		if( A <= sta[i] && sta[i] < B2 ) cnt3 ++ ;
		if( B2<= sta[i]                ) cnt4 ++ ;
	}
	if( cnt2 || cnt4 >= 2 ){ puts( "NO" ) ; return ; }

	if( !cnt4 ){ puts( ( cnt3 & 1 ) ? "YES" : "NO " ) ; return ; }

	if( ( cnt3 & 1 ) && cut_1_and_3( sta[topp] ) == true ){ puts( "YES" ) ; return ; }

	if( !( cnt3 & 1 ) && cut_1_or_3( sta[topp] ) == true ){ puts( "YES" ) ; return ; }

	puts( "NO" ) ;

}

int main(){
	scanf( "%d" , &T ) ;
	while( T -- ){
		scanf( "%d%d" , &A , &B ) ;
		scanf( "%s" , ss + 1 ) ;
		preWork() ; solve() ;
	}
}

你可能感兴趣的:(杂题(乱搞),------博弈论------)