[HAOI2015]数组游戏

题目大意:
  有一排n个格子,每个格子上都有一个白子或黑子,在上面进行游戏,规则如下:
  选择一个含白子的格子x,并选择一个数k,翻转x,2x,...,kx格子上的子。
  不能操作者负。

思路:
  将“某个格子上有一个白子 ”视作游戏的一个状态。
  对于状态x,sg(x)=mex{sg(2x),sg(2x)^sg(3x),sg(2x)^sg(3x)^...^sg(kx)}。
  由于SG函数的取值只与棋盘大小和棋子位置有关,因此我们可以记忆化。
  然后我们就有了暴力构造SG函数的程序,实测只能过40%的点,大力卡常以后勉强能50%。
  而且空间显然也开不下,只能用hash_map。
  然而这题的SG函数有一些神奇的性质,例如,对于大小为10的棋盘,当x分别为1~10时,sg(x)分别为:
  4 1 2 2 2 1 1 1 1 1
  我们将它们进行分组:
  (4)(1)(2)(2 2)(1 1 1 1 1)
  可以发现,当不同棋子可以往后跳的步数相同时,它们的SG函数相同。
  显然可以把它们分为2sqrt(n)组。
  其中前sqrt(n)组都是一个子一组,后sqrt(n)组都是很多个一组。
  这样,以sqrt(n)为界,对于我们需要的函数,判断一下参数的范围即可。

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cctype>
 4 inline int getint() {
 5     char ch;
 6     while(!isdigit(ch=getchar()));
 7     int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x;
10 }
11 const int N=100000;
12 int sg[N][2],mex[N];
13 int n,block;
14 inline int next(const int &x,const int &y) {
15     return x==y?x+1:y/(y/(x+1));
16 }
17 void getsg() {
18     for(register int i=1;i<=n;i=next(i,n)) {
19         for(register int k=2,tmp=0;k<=i;k=next(k,i)) {
20             int x=i/k;
21             int t=(x>block)?sg[n/x][1]:sg[x][0];
22             mex[tmp^t]=i;
23             if((i/x-i/(x+1))&1) tmp^=t;
24         }
25         int tmp=1;
26         while(mex[tmp]==i) tmp++;
27         ((i>block)?sg[n/i][1]:sg[i][0])=tmp;
28     }
29 }
30 int main() {
31     n=getint();
32     block=floor(sqrt(n));
33     getsg();
34     for(register int m=getint();m;m--) {
35         int ans=0;
36         for(register int w=getint();w;w--) {
37             const int x=getint();
38             ans^=(n/x>block)?sg[n/(n/x)][1]:sg[n/x][0];
39         }
40         puts(ans?"Yes":"No");
41     }
42     return 0;
43 }

暴力构造SG函数的程序: 

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cctype>
 4 #include<cstring>
 5 #include<ext/hash_map>
 6 inline int getint() {
 7     char ch;
 8     while(!isdigit(ch=getchar()));
 9     int x=ch^'0';
10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
11     return x;
12 }
13 __gnu_cxx::hash_map<int,int> sg,mex;
14 int n;
15 int getsg(const int x) {
16     if(sg.count(x)) return sg[x];
17     for(int k=2,tmp=0;k<=n/x;k++) {
18         tmp^=getsg(x*k);
19         mex[tmp]=x;
20     }
21     for(sg[x]=1;mex[sg[x]]==x;sg[x]++);
22     return sg[x];
23 }
24 int main() {
25     n=getint();
26     for(int i=n;i;i--) getsg(i);
27     for(int m=getint();m;m--) {
28         int ans=0;
29         for(int w=getint();w;w--) {
30             ans^=getsg(getint());
31         }
32         puts(ans?"Yes":"No");
33     }
34     return 0;
35 }
View Code

 

posted @ 2017-09-29 14:31  skylee03  阅读(160)  评论(0编辑  收藏  举报