转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
可惜没有机会去现场做,不过当时肯定是不会。
题意:有N堆石头,可以把两堆合成一堆,也可以把一堆去掉一个。
由于总数不变,最终总是要一个个拿完。那么有机会获胜的一方,肯定是先要把所有的合在一起,那么最终就拼奇偶数了。所以双方都要合并。总共就是sigma(ai)+n-1。
而且如果没有某堆只有一个的话,对方是阻挡不住的,没有取完,便被合并了。
所以就要考虑某堆只有一个的情况,单独考虑。
其中的操作包括:
把某堆只有一个的,取走
把两堆只有一个的,合并
把某堆只有一个的,合并给不是一个的
把不是一个的,取走一个
采用记忆化搜索
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define N 10005 7 #define LL long long 8 #define inf 1<<29 9 #define eps 1e-7 10 using namespace std; 11 int sg[55][60005]; 12 int get_sg(int i,int j){ 13 if(sg[i][j]!=-1) 14 return sg[i][j]; 15 if(j==1) 16 return sg[i][j]=get_sg(i+1,0); 17 sg[i][j]=0; 18 //某堆只有一个的取掉 19 if(i>=1&&!get_sg(i-1,j)) 20 sg[i][j]=1; 21 //把不是1个的取走一个 22 else if(j>=1&&!get_sg(i,j-1)) 23 sg[i][j]=1; 24 //把1个的合并给不是1个的 25 else if(i>=1&&j>0&&!get_sg(i-1,j+1)) 26 sg[i][j]=1; 27 //把两个1个的合并,其中注意,合并是需要一步的 28 else if(i>=2&&((j==0&&!get_sg(i-2,j+2))||(j&&!get_sg(i-2,j+3)))) 29 sg[i][j]=1; 30 return sg[i][j]; 31 } 32 int main(){ 33 int n,t,cas=0,k; 34 scanf("%d",&t); 35 memset(sg,-1,sizeof(sg)); 36 while(t--){ 37 scanf("%d",&n); 38 int one=0,sum=0; 39 while(n--){ 40 scanf("%d",&k); 41 if(k==1) 42 one++; 43 else 44 sum+=(k+1); 45 } 46 if(sum) 47 sum--; 48 printf("Case #%d: ",++cas); 49 if(get_sg(one,sum)) 50 puts("Alice"); 51 else 52 puts("Bob"); 53 } 54 return 0; 55 }