把题读错了。。。
对自己感到无语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 lenB≤len<A 为2类串
A ≤ l e n < 2 × B A\leq len<2\times B A≤len<2×B 为3类串
2 × B ≤ l e n 2\times B \leq len 2×B≤len 为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() ;
}
}