hdu 3032Nim or not Nim?<sg函数>

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3032

题意:Alice和Bob轮流取N堆石子,每堆S[i]个,Alice先,每一次可以从任意一堆中拿走任意个石子,也可以将一堆石子分为两个小堆。先拿完者获胜。

数据范围: (1 ≤ N ≤ 10^6, 1 ≤ S[i] ≤ 2^31 - 1).

思路: 此题为博弈中的—取走-分割游戏这种游戏允许取走某些东西,然后将原来的一个游戏分成若干个相同的游戏)

由于数据范围,不能直接求sg值只能打表找规律;

有SJ 定理:

对于任意的一个 Anti-SG 游戏,如果我们规定当局面中所有单一游戏的 SG 值为 0 时游戏 结束,则先手必胜当且仅当以下两个条件满足任意一个:

(1)游戏的 SG 函数不为 0,且游戏中某个单一游戏的 SG 函数大于1。

(2)游戏的 SG 函数为 0,且游戏中没有单一游戏的 SG 函数大于 1。

 

 

View Code
 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <string>
 6 #include <stdlib.h>
 7 #include <algorithm>
 8 using namespace std;
 9 typedef long long LL;
10 const LL Mod= 1e9+7;
11 int T, N, x;
12 int sg[10000];
13 int mex(int x) // 求sg函数 
14 {
15     if( sg[x]>0 )return sg[x];
16     bool re[10000]={0};
17     for( int i=0; i<x; ++ i ){
18         re[mex(i)]=1;
19         if( x-i>0&&i>0 )re[mex(i)^mex(x-i)]=1;
20     }
21     int i=0;
22     while( re[i] )i++;
23     return sg[x]=i;
24 }
25 
26 int main( )
27 {
28 /*    memset( sg, -1, sizeof sg );
29     sg[0]=0;
30     for( int i=0; i<100; ++ i )
31         printf( "%d\n", mex( i ) );
32 */
33     scanf( "%d", &T );
34     while( T-- ){
35         scanf( "%d", &N );
36         int ans=0;
37         for( int i=0; i<N; ++ i ){
38             scanf( "%d", &x );
39             if( x%4==0 )ans^=(x-1);
40             else if( x%4==3 )ans^=(x+1); 
41             else ans^=x;
42         }
43         if( ans!=0 )puts( "Alice" );
44         else puts( "Bob" ); 
45     }
46     return 0;
47 }

 

 

原文地址:https://www.cnblogs.com/jian1573/p/3050533.html