The only difference between the easy and hard versions is that the given string ss in the easy version is initially a palindrome, this condition is not always true for the hard version.
A palindrome is a string that reads the same left to right and right to left. For example, "101101" is a palindrome, while "0101" is not.
Alice and Bob are playing a game on a string ss of length nn consisting of the characters '0' and '1'. Both players take alternate turns with Alice going first.
In each turn, the player can perform one of the following operations:
Reversing a string means reordering its letters from the last to the first. For example, "01001" becomes "10010" after reversing.
The game ends when every character of string becomes '1'. The player who spends minimum dollars till this point wins the game and it is a draw if both spend equal dollars. If both players play optimally, output whether Alice wins, Bob wins, or if it is a draw.
The first line contains a single integer t (≤t≤10^3). Then tt test cases follow.
The first line of each test case contains a single integer n (1≤n≤10^3).
The second line of each test case contains the string s of length n, consisting of the characters '0' and '1'. It is guaranteed that the string s contains at least one '0'.
Note that there is no limit on the sum of nn over test cases.
For each test case print a single word in a new line:
3
3
110
2
00
4
1010
ALICE
BOB
ALICE
题目大意为:给一个字符串,Alice与Bob交替进行操作1或2。
字符串中的字符全变为1时,花费最少者获胜。(当然,不考虑任何一方消极游戏的情况)
先从简单版说起。其中,Alice初始拿到的字符串即为回文(这也是简单版与困难版的唯一区别)(由回文,易得简单版中Alice不得不先进行操作1,使其堪称Alice的困难模式)。此时,游戏胜负取决于字符串中0的个数。分析以下情况:
代码如下:
#include
using namespace std;
int main()
{
int n,t,num;
char c;
cin>>t;
while(t--)
{
cin>>n;
getchar();
int cnt=0;
for(int i=1;i<=n;i++)
{
cin>>c;
num=c-'0';
if(!num)cnt++;
}
if(!(cnt%2)||cnt==1)cout<<"BOB"<
再考虑复杂版。笔者最先想到的思路是先判断初始字符串是否回文。若为真则可按简单版处理,若为假则另辟蹊径。当初始字符串不回文时,先手的Alice时十分舒服的,分为以下两情况。
需要注意的是,即便Alice以上两情况中打得很爽,她也不能稳赢。在前一种情况中,假如她“大E”了,把只有一个0的回文串给到Bob ,忘记自己如何在简单版的情况2中败北 ,那么两人均只操作了一次,打平。(原始字符串长度为奇数,只含有两个0,其中一个在中间。例如“11010”)这种情况下Alice能否取胜的?她可否重置一下就把字符串丢给Bob呢?本以为Bob会一脸无奈地接盘,没想到他双眼燃起光芒。只见他把不在中间的0置换为1,Alice只得置换中间的0,仍旧打平。Alice“大意失荆州”也好,Bob“顽强逼平”也罢, 平局是双方在此情景的最好局面(这个残酷的游戏竟有次和谐一面,也是实属难得)
代码如下:
#include
using namespace std;
int main()
{
int n,t,num;
char c;
cin>>t;
while(t--)
{
cin>>n;
getchar();
int cnt=0,cou=0;
int a[1007];
for(int i=1;i<=n;i++)
{
cin>>c;
num=c-'0';
a[i]=num;
if(!num)cnt++;
}
for(int i=1;i<=n/2;i++)
{
if(a[i]!=a[n-i+1]){
cou++;
}
}
if(cou)
{
if(cou==1&&cnt==2) cout<<"DRAW"<
其中cnt记录字符串中0的个数,cou记录转化为回文所需要的操作步数。
本题的解析到这里也就可以结束了,但是我 偏不 总觉得讨论起来有点麻烦,而且在简单和复杂版本中,均有涉及到同一特殊情况,可否二者合并呢?其实,稍加分析可知 (从简单版中Alice占据先手,却被回文字符串整得十分狼狈看出) ,本游戏的取胜之道,即是不断将回文的字符串甩给对手。因为每接到不全为1的回文字符串,游戏局面转化为简单版的情况1,接到字符串者难以获胜。可以说谁先将字符串改造为回文,谁就基本占据了主动权。是所以说是基本,是因为如果字符串长度为奇数,且不止中间位置一处为0,则仍会败北。对方只需先把中间的0置换为1,就把主动权夺回来了, 小丑竟又成了你自己。
既然奇数长度字符串中间的0足以逆转胜负,先手可否抢先“占据”这个战略要地?非也!如果把先手优势用在此处,对方将可以造出偶数个0的回文字符串,锁定胜局。更何况,在形如“1010110”的情况时,牢牢占据制造回文字符串的主动权,你也可以获得胜利。
明确了这一游戏策略后,就不难发现,简单版所研究的内容,恰好可以看作是复杂版中字符串到达回文状态后的情况。我们可以把游戏分为两个部分:转化为回文的部分 (争夺战略要地) ,和回文后的部分 (大局已定) 。如果初始字符串非回文,先手者会在第一阶段取得少付出1个代价的优势。如果开局即回文,则先手的优势丧失。在第二阶段,依据回文字符串的形态,即可判断两者谁可以在本阶段少付出1个代价。将两阶段结果叠加,即可得知最终的胜者。
综上所述,若Bob想获胜,初始字符串不仅要回文,还有其它限制,即长度为偶数,或者为奇数且只含一个零(即中间位置的0)。即他既要追求字符串开局即回文(让Alice享受不了先手优势),又要保证回文字符串形态有利。当初始字符串不为回文,长度为奇数,且中间和另一位置为0时,二者必然打平。此外情况,Alice必然获胜。一言以蔽之,谁将含偶数个或1个0的回文字符串甩给对手,谁就获得了最终的胜利。