zoukankan      html  css  js  c++  java
  • 【BZOJ 4035】 4035: [HAOI2015]数组游戏 (博弈)

    4035: [HAOI2015]数组游戏

    Time Limit: 15 Sec  Memory Limit: 32 MB
    Submit: 181  Solved: 89

    Description

    有一个长度为N的数组,甲乙两人在上面进行这样一个游戏:首先,数组上有一些格子是白的,有一些是黑的。然
    后两人轮流进行操作。每次操作选择一个白色的格子,假设它的下标为x。接着,选择一个大小在1~n/x之间的整数
    k,然后将下标为x、2x、...、kx的格子都进行颜色翻转。不能操作的人输。现在甲(先手)有一些询问。每次他
    会给你一个数组的初始状态,你要求出对于这种初始状态他是否有必胜策略。

    Input

    接下来2*K行,每两行表示一次询问。在这两行中,第一行一个正整数W,表示数组中有多少个格子是白色的,第二
    行则有W个1~N之间的正整数,表示白色格子的对应下标。

    Output

     对于每个询问,若先手必胜输出"Yes",否则输出"No"。答案之间用换行隔开

    Sample Input

    3
    2
    2
    1 2
    2
    2 3

    Sample Output

    Yes
    No
    【样例解释】
    在第一个询问中,甲选择点1,然后将格子1*1和2*1翻过来即可。
    第二个询问中,无论甲选择哪个点,都只能翻掉一个格子。乙只需
    翻掉另一个格子就行了。
    N<=1000000000 , K,W<=100 , 不会有格子在同
    一次询问中多次出现。

    HINT

    Source

    【分析】

      

      把每一个白点看成是一个子游戏,最后将SG函数全部异或起来即可,由SG定理可知有:

          $SG(i)$ = $mex${$SG[i*1]$^$SG[i*2]$^$...$ ^ $SG[i*k]$},$k=[2,N/i]$。

      这个第一步应该想到的,但是这样子直接暴力不行。

      实际上某一个SG[i]函数的值只和N/i有关,因此有用的状态只有$O(sqrt n)$个。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 #include<cmath>
     7 using namespace std;
     8 #define Maxn 500010
     9 
    10 int n,sq,sg[2][Maxn];
    11 int w[Maxn],wl;
    12 bool vis[Maxn];
    13 
    14 int nxt(int x,int y) {return x==y?y+1:y/(y/(x+1));}
    15 
    16 void init()
    17 {
    18     memset(vis,0,sizeof(vis));
    19     for(int i=1;i<=n;i=nxt(i,n))
    20     {
    21         wl=0;int now=0;
    22         for(int j=2;j<=i;j=nxt(j,i))
    23         {
    24             int x=i/j;
    25             int nw=(x>sq)?sg[1][n/x]:sg[0][x];
    26             // if(!((i/x-i/(x+1))&1)) continue;
    27             w[++wl]=now^nw;
    28             vis[w[wl]]=1;
    29             // now^=nw;
    30             if((i/x-i/(x+1))&1) now^=nw;
    31         }
    32         now=1;
    33         while(vis[now]) now++;
    34         if(i>sq) sg[1][n/i]=now;
    35         else sg[0][i]=now;
    36         for(int j=1;j<=wl;j++) vis[w[j]]=0;
    37     }
    38 }
    39 
    40 int main()
    41 {
    42     scanf("%d",&n);
    43     sq=(int)sqrt((double)n);
    44     init();
    45     int T;
    46     scanf("%d",&T);
    47     while(T--)
    48     {
    49         int sm,ans=0;scanf("%d",&sm);                                                                                                                
    50         while(sm--)
    51         {
    52             int x;
    53             scanf("%d",&x);
    54             ans^=(n/x>sq)?sg[1][x]:sg[0][n/x];
    55         }
    56         if(ans) printf("Yes
    ");
    57         else printf("No
    ");
    58     }
    59     return 0;
    60 }
    View Code

    不会打,膜了一下lych_cys的代码。。

    判断&1那里是如果有偶数个相同的,异或起来等于0,就不用异或进去了。

    2017-04-11 10:58:52

  • 相关阅读:
    javascript一个重要知识点:事件。
    null和undifned的区别
    javascript中常用数组方法详细讲解
    在网站中数据缓存的重要性
    谈谈我对闭包知识的深刻理解
    FormData上传文件(不是所有的浏览器都支持)
    iframe+form表单提交数据
    伪AJAX
    ajax之发送post请求
    AJAX之发送GET请求
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6692581.html
Copyright © 2011-2022 走看看