[CSAcademy]A-Game
题目大意:
给你一个只含字符'A'和'B'的串,A和B两人轮流对其中的子串染色,要求被染色的子串中不包含已经被染色的子串。
最后,如果一方染的'A'少,那么这一方胜;
如果双方染的'A'和'B'一样多,那么就是平局。
问哪一方有必胜策略,或是都没有必胜策略。
思路:
首先可以想到一个贪心的做法:
当字符串中还有'B'的时候,取一段全'B'子串;
当字符串中只剩下'A'的时候,不得不取'A',这时候双方轮流取一个。
显然,当'A'的数量为偶数时,由于双方都轮流取一个'A',最后双方取的'A'一样多,那么一定是平局。
当'A'的数量为奇数时,显然有一方会多取一个'A',而且一定是先开始取'A'的一方输。
那么问题就转化成了如果只取'B',最后不能取的一方输(因为只能取'A'了)。
这就变成了一个经典的Nim游戏模型。
我们把每一段连续的'B'当作一个子游戏,把'B'的数量当作游戏的状态。
对于一个状态x,sg(x)=mex{sg(y)|y是x的后继状态}。
显然,由于题目没有特殊的限制,x的后继状态总是0~x-1的所有状态。
那么显然sg(x)=x。
1 #include<cstdio> 2 #include<cctype> 3 inline int getint() { 4 register char ch; 5 while(!isdigit(ch=getchar())); 6 register int x=ch^'0'; 7 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 8 return x; 9 } 10 inline char getupper() { 11 register char ch; 12 while(!isupper(ch=getchar())); 13 return ch; 14 } 15 inline int getsg(const int &x) { 16 return x; 17 } 18 int main() { 19 int n=getint(); 20 int tota=0,ans=0,cnt=0; 21 for(int i=1,ch='\0',last;i<=n;i++) { 22 last=ch; 23 ch=getupper(); 24 if(ch=='A') { 25 tota++; 26 if(last=='B') { 27 ans^=getsg(cnt); 28 cnt=0; 29 } 30 } else { 31 cnt++; 32 } 33 } 34 ans^=getsg(cnt); 35 if(tota&1) { 36 puts(ans?"A":"B"); 37 } else { 38 puts("-1"); 39 } 40 return 0; 41 }