Description
Alice and Bob are very smart guys and they like to play all kinds of games in their spare time. The most amazing thing is that they always find the best strategy, and that’s why they feel bored again and again. They just invented a new game, as they usually did.
The rule of the new game is quite simple. At the beginning of the game, they write down N random positive integers, then they take turns (Alice first) to either:
1. Decrease a number by one.
2. Erase any two numbers and write down their sum.
Whenever a number is decreased to 0, it will be erased automatically. The game ends when all numbers are finally erased, and the one who cannot play in his(her) turn loses the game.
Here’s the problem: Who will win the game if both use the best strategy? Find it out quickly, before they get bored of the game again!
Input
The first line contains an integer T(1 <= T <= 4000), indicating the number of test cases.
Each test case contains several lines.
The first line contains an integer N(1 <= N <= 50).
The next line contains N positive integers A 1 ….A N(1 <= A i <= 1000), represents the numbers they write down at the beginning of the game.
Output
For each test case in the input, print one line: “Case #X: Y”, where X is the test case number (starting with 1) and Y is either “Alice” or “Bob”.
Sample Input
3
3
1 1 2
2
3 4
3
2 3 5
Sample Output
Case #1: Alice
Case #2: Bob
Case #3: Bob
Source
2011 Asia ChengDu Regional Contest
题意:有一堆的数字,两种操作:1:将某一个数值减1、2:将两个数字合并
解法:SG[i][j]表示有i个石子数为1的堆数,其它堆合并再取完的步数为j。直接SG扫就好了。。。
有几个地方重点说一下,我最开始也是没理解,后来懂了。。
(1)if(one>=1&&!getSG(one-1,sumstep)) return SG[one][sumstep]=1;
比赛时和菊苣手动模拟了一下,其实每一种状态,不管是怎样合并或取数只要子状态里出现了先手必输的状态,因此该状态可以转移到让对手必输,所以自己必赢。。。(也就只有这个点比赛时发现了)
(2) if(one>=1&&sumstep>=1&&!getSG(one-1,sumstep+1)) return SG[one][sumstep]=1;
将一个1合并到非1的上去,其他的操作步数为什么时+1,而不是2(合并+去掉),因为+2其实就是他本身的等价状态并不是子状态。+1(去掉)才是子状态。同理类推第四种情况的时候。
/*
#include<bits/stdc++.h>
using namespace std;
int SG[55][55000];
//SG[i][j]表示有i个石子数为1的堆数,其它堆合并再取完的步数为j。
//若值为1则先取者胜,为0为先取者输
int getSG(int one,int sumstep){
if(SG[one][sumstep]!=-1) return SG[one][sumstep];
//没有1的时候就是各取一个
if(one==0&&sumstep%2==1) return SG[one][sumstep]=1;
else if(one==0&&sumstep%2==0) return SG[one][sumstep]=0;
//当其他的步数为1时,
if(sumstep==1) return SG[one][sumstep]=getSG(one+1,0);
//只要找到一种是输的其他状态。那他就能赢
SG[one][sumstep]=0;
//1的个数去掉一个
if(one>=1&&!getSG(one-1,sumstep)) return SG[one][sumstep]=1;
//非1的个数去掉一个
if(sumstep>=1&&!getSG(one,sumstep-1)) return SG[one][sumstep]=1;
//将1的合并到非1的上去
if(one>=1&&sumstep>=1&&!getSG(one-1,sumstep+1)) return SG[one][sumstep]=1;
//将两个1的合并
if(one>=2){
//非1的为0,相当于将一个1加到另一个1上,
if(sumstep==0&&!getSG(one-2,sumstep+2)) return SG[one][sumstep]=1;
//非1的为0,相当于将两个1加到非1上,
else if(sumstep!=0&&!getSG(one-2,sumstep+3)) return SG[one][sumstep]=1;
}
return SG[one][sumstep];
}
int main(){
int t;
scanf("%d",&t);
memset(SG,-1,sizeof(SG));
for(int cas=1;cas<=t;cas++){
int n;
int one=0,sumstep=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if(x==1) one++;
else sumstep+=x+1;//合并,去掉
}
if(sumstep) sumstep--; //合并为p-1次,
if(getSG(one,sumstep)) printf("Case #%d: Alice\n",cas);
else printf("Case #%d: Bob\n",cas);
}
return 0;
}
*/
//按模板来写一个。。。
#include<bits/stdc++.h>
using namespace std;
int SG[55][55000];
int getSG(int one,int sumstep){
if(SG[one][sumstep]!=-1) return SG[one][sumstep];
if(one==0&&sumstep%2==1) return SG[one][sumstep]=1;
else if(one==0&&sumstep%2==0) return SG[one][sumstep]=0;
if(sumstep==1) return SG[one][sumstep]=getSG(one+1,0);
//SG[one][sumstep]=0;
bool visit[2];
memset(visit,false,sizeof(visit));
if(one>=1) visit[!getSG(one-1,sumstep)]=true;
if(sumstep>=1)visit[!getSG(one,sumstep-1)]=true;
if(one>=1&&sumstep>=1) visit[!getSG(one-1,sumstep+1)]=true;
if(one>=2){
if(sumstep==0) visit[!getSG(one-2,sumstep+2)]=true;
else visit[!getSG(one-2,sumstep+3)]=true;
}
if(visit[1]==true) return SG[one][sumstep]=1;//推出来的
else return SG[one][sumstep]=0;
}
int main(){
int t;
scanf("%d",&t);
memset(SG,-1,sizeof(SG));
for(int cas=1;cas<=t;cas++){
int n;
int one=0,sumstep=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if(x==1) one++;
else sumstep+=x+1;//合并,去掉
}
if(sumstep) sumstep--; //合并为p-1次,
if(getSG(one,sumstep)) printf("Case #%d: Alice\n",cas);
else printf("Case #%d: Bob\n",cas);
}
return 0;
}
/*
3
3
1 1 2
2
3 4
3
2 3 5
Case #1: Alice
Case #2: Bob
Case #3: Bob
*/