HOJ 2645 WNim

HOJ 2645 WNim
  lord wu给去年省赛出的一个题目,今天终于给搞出来了。
  一开始完全想错了方向,总是觉得很复杂。后来发现计算SG值的时候,对于限制的状态只能走到0,也就是必胜态,这样就是一个裸的SG分解的题目了。接下来就很简单了,利用容斥原理算出SG值,结论同Nim。
  感觉博弈的题目做起来还是很困难的,一方面SG值的计算不容易,很多时候只能通过规约成一个经典模型来计算;另一方面博弈的题目变化多端,很难有什么规律可言。不过SG分解还是王道,用这个武器解决简单的博弈问题还是绰绰有余的。
附2645代码:
 1  #include  < cstdio >
 2  const   int  N  =   12 ;
 3 
 4  int  p[N], ans;
 5  long   long  gcd( long   long  a,  long   long  b)
 6  {
 7       return  b  ==   0   ?  a : gcd(b, a  %  b);
 8  }
 9  void  calc_sg( long   long  tol,  int  m,  int  dep,  long   long  v,  bool  mark)
10  {
11       if  (dep  ==  m)
12      {
13           if  (mark)   ans  -=  tol  /  v;
14           else         ans  +=  tol  /  v;
15           return ;
16      }
17      calc_sg(tol, m, dep  +   1 , v, mark);
18       if  (v  <=  tol)
19          calc_sg(tol, m, dep  +   1 , v  /  gcd(v, p[dep])  *  p[dep], mark  ^   1 );
20  }
21 
22  int  main()
23  {
24       int  T, m, n, a, g;
25 
26      scanf( " %d " & T);
27       while  (T -- )
28      {
29          g  =   0 ;
30           bool  mark  =   1 ;
31          scanf( " %d %d " & m,  & n);
32           for  ( int  i  =   0 ; i  <  m; i ++ )
33              scanf( " %d " & p[i]);
34           for  ( int  i  =   0 ; i  <  n; i ++ )
35          {
36              scanf( " %d " & a);
37               if  ( ! mark)   continue ;
38              ans  =   0 ;
39              calc_sg(a, m,  0 1 0 );
40              g  ^=  ans;
41               for  ( int  j  =   0 ; j  <  m; j ++ )
42                   if  (a  %  p[j]  ==   0 )
43                  {
44                      mark  =   0 ;
45                       break ;
46                  }
47          }
48           if  ( ! mark)  puts( " Xiao Hong " );
49           else     printf( " %s\n " , g  ?   " Xiao Hong "  :  " Xiao Gang " );
50      }
51 
52       return   0 ;
53  }
54 


你可能感兴趣的:(HOJ 2645 WNim)