【Foreign】石子游戏 [博弈论]

石子游戏

Time Limit: 10 Sec  Memory Limit: 256 MB

Description

  

Input

  

Output

  输出T行,表示每组的答案。

Sample Input

  3
  1
  1
  2
  1
  0 0
  3
  1 2 2
  4 4 4 4

Sample Output

  1
  0
  6

HINT

  

Solution

  这显然是一道博弈论的题目。我们发现这是一个树结构,仔细看了一下,发现这显然是一个阶梯Nim的模型。

  我们将所有和同n奇偶的值XOR起来就可以得到SG。我们先判断一下,若SG=0则显然必败,否则必胜。

  然后我们开始计算方案,枚举每一个节点,目标显然就是要让SG=0

  由于XOR的消去率,根据题意,可以分 2 种情况分别讨论:(根据SG异或值判断是加入还是取出。)

  1. 从父亲那加入值,显然就是需要 ( SG^a[这个点] ) - a[这个点的父亲] <= a[这个点],这样才可以通过加入若干个值使得SG=0;
  2. 把值给儿子,显然需要 (SG^a[这个点]) <= a[这个点],这样才可以通过拿走若干的值使得SG=0。

  然后我们讨论一下是否为叶子节点

  1. 非叶节点,若从父亲那加入值只有1的贡献,把值给儿子(由于有两个儿子)所以贡献为2;
  2. 叶子节点,从父亲那加入值或者彻底删去都显然只有1的贡献。

  这样就可以求出方案数了。

Code

 1 #include<iostream>  
 2 #include<algorithm>  
 3 #include<cstdio>  
 4 #include<cstring>  
 5 #include<cstdlib>  
 6 #include<cmath>  
 7 using namespace std;
 8 
 9 const int ONE = 10001;
10 const int INF = 214783640;
11 const int MOD = 1e9+7;
12 
13 int T;
14 int n;
15 int x,num;
16 int a[17][65537];
17 int SG,Ans;
18 
19 int get()
20 { 
21         int res=1,Q=1;    char c;
22         while( (c=getchar())<48 || c>57)
23         if(c=='-')Q=-1;
24         if(Q) res=c-48; 
25         while((c=getchar())>=48 && c<=57) 
26         res=res*10+c-48; 
27         return res*Q; 
28 }
29 
30 void Solve()
31 {
32         n=get();
33         SG=Ans=0;
34         for(int i=1;i<=n;i++)
35         for(int j=1;j<=(1<<(i-1));j++)
36         {
37             a[i][j]=get();
38             if(i%2==n%2)    SG ^= a[i][j];
39         }
40         if(!SG) {printf("0"); return;}
41         
42         for(int i=1;i<=n;i++)
43         {
44             for(int j=1;j<=(1<<(i-1));j++)
45             if(i%2==n%2)
46             {
47                 if(i!=n)
48                 {
49                     if( (SG^a[i][j]) <= a[i][j]) Ans+=2;
50                     if( (SG^a[i][j]) > a[i][j] && (SG^a[i][j]) - a[i-1][(j-1)/2+1] <= a[i][j]) Ans+=1;
51                 }
52                 if(i==n)
53                 {
54                     if( (SG^a[i][j]) <= a[i][j] ) Ans++;
55                     if( (SG^a[i][j]) > a[i][j] && (SG^a[i][j]) - a[i-1][(j-1)/2+1] <= a[i][j] ) Ans++;
56                 }
57             }
58         }
59         
60         printf("%d",Ans);
61 }
62 
63 int main()
64 {      
65         T=get();
66         while(T--)
67             Solve(),printf("
");
68 }
View Code
原文地址:https://www.cnblogs.com/BearChild/p/6516279.html