題目:有N堆石頭,可以把兩堆合成一堆,也可以把一堆去掉一個。問先手必勝還是先手必敗
思路:所有石子個數大於1的石子堆ai可以看成一堆石子數爲sigma(ai)+n-1的堆,因爲個數大於1的石子堆的合併,對方是無法阻擋的。但是1是可以阻擋的。
每次的操作有:
讓石子數 爲1的堆數減1
合併堆的石子數減1
合併兩個個數爲1的石子堆
把1合併到合併堆上去
代碼:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
//0x3f3f3f3f
const int maxn=6e4+50;
int sg[55][maxn];
int get_sg(int x,int y){
if(sg[x][y]!=-1)
return sg[x][y];
if(y==1) return sg[x][y]=get_sg(x+1,0);
sg[x][y]=0;
if(x>=1&&get_sg(x-1,y)==0)
sg[x][y]=1;
else if(y>0&&get_sg(x,y-1)==0)
sg[x][y]=1;
else if(x>=1&&y>0&&get_sg(x-1,y+1)==0)
sg[x][y]=1;
else if(x>=2&&((y==0&&get_sg(x-2,y+2)==0)||(y>0&&get_sg(x-2,y+3)==0)))
sg[x][y]=1;
return sg[x][y];
}
int main(){
int T,cas=0,n,cnt,sum,x;
mm(sg,-1);
scanf("%d",&T);
while(T--){
scanf("%d",&n);
cnt=sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(x==1) cnt++;
else sum+=(x+1);
}
if(sum) sum--;
int ans=get_sg(cnt,sum);
if(ans>0) printf("Case #%d: Alice\n",++cas);//先手必勝
else printf("Case #%d: Bob\n",++cas);//先手必敗
}
return 0;
}