可以看到S[i]的值可能非常大,如果计算每一堆的sg值是不现实的,所以需要我们找规律来计算给定的石堆的sg值。
找了半天规律,但是WA了,说明规律不对。
此题为博弈中的—取走-分割游戏(这种游戏允许取走某些东西,然后将原来的一个游戏分成若干个相同的游戏)
例1:Lasker's Nim游戏:每一轮允许两会中操作之一:①、从一堆石子中取走任意多个,②、将一堆数量不少于2的石子分成都不为空的两堆。
分析:很明显:sg(0) = 0,sg(1) = 1。
状态2的后继有:0,1和(1,1),他们的SG值分别为0,1,0,所以sg(2) =2。
状态3的后继有:0、1、2、(1,2),他们的SG值分别为0、1、2、3,所以sg(3) = 4。
状态4的后继有:0、1、2、3、(1,3)和(2,2),他们的SG值分别为0,1,2,4,5,0,所以sg(4) = 3.
再推一些,推测得到:对于所有的k >= 0,有 sg( 4k+1 ) = 4k+1; sg( 4k+2 ) = 4k+2; sg( 4k+3 ) = 4k+4; sg( 4k+4 ) = 4k+3。
假设游戏初始时有3堆,分别有2、5和7颗石子。三堆的SG函数值分别为2、5、8,他们的Nim和等于15.所以要走到P状态,就要使得第三堆的SG值变成7,可以将第三对按1和6分成两堆。
#include <iostream> using namespace std; int main() { int t,n,a; cin >> t; while( t-- && cin >> n ) { int s = 0 ; for( int i = 0; i < n; i++ ) { cin >> a; if( a % 4 == 3 ) s ^= (a+1); else if( a % 4 == 0) s ^= (a-1); else s ^= a; } if( s == 0 ) cout << "Bob\n"; else cout << "Alice\n"; } return 0; }
//得到SG值,找出SG值的规律。 /*sg[4k]=4k-1 sg[4k+1]=4k+1 sg[4k+2]=4k+2 sg[4k+3]=4k+1 #include <iostream> using namespace std; #include<string.h> const int MAX = 1005; int sg[MAX]; bool vst[MAX]; void take_part(int n) { for(int i = 1; i <= n / 2; i++) { int yihuo = 0; yihuo ^= sg[i] ^ sg[n - i]; vst[yihuo] = true; } } void get_sg() { memset(sg, 0, sizeof(sg)); for(int i = 0; i < MAX; i++) { memset(vst, false, sizeof(vst)); int j = 0; while(j++ < i) { vst[sg[j]] = true; } take_part(i); for(int j = 0; j < MAX; j++) { if(!vst[j]) { sg[i] = j; break; } } } return ; } void view_arr(int a[], int n) { for(int i = 0; i < n; i++) { cout << "sg[" << i << "]" << ": " << a[i] << endl; } return ; } int main(void) { int cas; get_sg(); view_arr(sg, 30); return 0; } */