acdreamoj1112 sg函数

.Here a*b = n and a > 1 and b > 1.For example, Alice can replace 6 with 2 or 3 or (2, 3).But he can’t replace 6 with 6 or (1, 6). But you can replace 6 with 1. 

对于n个数,相当于n个局面,只要将n个局面异或起来就好了,所以我们就考虑一个数的时候的情况。

如果我们把x写成质数的幂相乘的形式就是p1^a1 * p2 ^ a2 * p3 ^ a3…*pm ^ am

sum = a1 + a2 + a3 + …. am;

操作的本质其实就是给一些指数降幂,也就是可以把sum变成(0 – > sum-1)中的任何一个数,或者变成h1 ,h2的形式,h1 + h2 = sum

h1, h2分别是两个因子对应的sum,相当于sum这个局面可以变成若干的子局面。用SG搞搞就出来了。

SG其实就是在子局面中找一个最小的未被访问过的数当做当前局面的值,如果你只想套结论的话这样就够用了。

const  int maxn = 5000000 ;
int    sum[maxn+8]  ;
int    prime[maxn+8]  , primesize ;
bool   is[maxn+8]  ;

void   make(){
       memset(is , 0 , sizeof(is)) ;
       is[1] = 1 , sum[1] = 0  ;
       primesize = 0 ;
       for(int i = 2 ; i <= maxn ; i++){
            if(! is[i]){
                 prime[primesize++] = i ;
                 sum[i] = 1 ;
            }
            for(int j = 0 ; j < primesize ; j++){
                  if(i * prime[j] > maxn)  break ;
                  is[i * prime[j]] = 1 ;
                  sum[i * prime[j]] = sum[i] + 1 ;
                  if(i % prime[j] == 0) break  ;
            }
       }
}


int   sg[35] ;
int   dfs(int n){
      if(sg[n] != -1) return sg[n] ;
      bool vis[35] ;
      memset(vis , 0 , sizeof(vis)) ;
      for(int i = 0 ; i < n ; i++)  vis[dfs(i)] = 1 ;
      for(int i = 1 ; i < n ; i++)  vis[dfs(i) ^ dfs(n-i)] = 1 ;
      int s = 0 ;
      while(vis[s]) s++ ;
      return sg[n] = s  ;
}

int   main(){
      make() ;
      memset(sg , -1 , sizeof(sg)) ;
      sg[0] = 0 ;
      for(int i = 1 ; i <= 33 ; i++) sg[i] = dfs(i) ;
      int n  , s  , x  , i ;
      while(scanf("%d" , &n) != EOF){
            s = 0 ;
            for(i = 1 ; i <= n ; i++){
                scanf("%d" , &x) ;
                s ^= sg[sum[x]] ;
            }
            if(s)  puts("Alice") ;
            else   puts("Bob")   ;
      }
      return  0 ;
}



你可能感兴趣的:(acdreamoj1112 sg函数)