题目链接:https://cn.vjudge.net/problem/POJ-3537
题目大意:
给你一个1*n的图,然后每一次你可以选一个地方放置一个‘X’,然后问你谁会先构成三个相邻的‘X’。
具体思路:
当我们在一个地方放置棋子的时候,这个位置往左边两个,往右边两个都是不能放置的,因为你先手放置的话,对手只要在这四个位置放置的话,必输。
然后每个人都要尽量的避免这个局势,所以肯定会在这个点左边两个的位置选择,这个点右边两个点开始放置。
然后对于当前的长度i。我们就可以枚举位置 j (1 < = j < = i ),每一次是sg[j-2]^sg[i-j-2]的结果,然后sg打表就可以了。
对于这种博弈,我们可以将它看成每一次是放置一个长度为5的棋子,然后这个棋子两边的的大小是他的子状态。
AC代码:
1 #include<iostream>
2 #include<map>
3 #include<string>
4 #include<cstring>
5 using namespace std;
6 # define inf 0x3f3f3f3f
7 # define ll long long
8 const ll mod = 998244353;
9 const int maxn = 2e3+100;
10 map<int,int>sg;// 防止越界,可以考虑用map
11 int vis[maxn];
12 void init()
13 {
14 sg[0]=0;
15 for(int i=1; i<maxn; i++)
16 {
17 memset(vis,0,sizeof(vis));
18 // vis[sg[i-3]]=1;
19 // vis[sg[i-4]]=1;
20 // vis[sg[i-5]]=1;
21 for(int j=1; j<=i; j++)
22 {
23 vis[ sg[j-3] ^ sg[i-j-2]]=1;
24 }
25 for(int j=0; j<maxn; j++)
26 {
27 if(!vis[j])
28 {
29 sg[i]=j;
30 break;
31 }
32 }
33 }
34 }
35
36 int main()
37 {
38 init();
39 // freopen("hqx.in","w",stdout);
40 for(int i=1; i<=2000; i++)
41 {
42 if(!sg[i])
43 cout<<i<<endl;
44 }
45 // for(int i=1; i<10; i++)
46 // {
47 // cout<<i<<" "<<sg[i]<<endl;
48 // }
49 sg[6]=1;
50 sg[20]=1;
51 sg[42]=1;
52 sg[82]=1;
53 sg[88]=1;
54 sg[96]=1;
55 sg[116]=1;
56 sg[138]=1;
57 sg[146]=1;
58 sg[1524]=1;
59 int n;
60 while(cin>>n)
61 {
62 if(sg[n]==0)
63 cout<<"1"<<endl;
64 else
65 cout<<"2"<<endl;
66 }
67 return 0;
68 }