[HAOI2015]数组游戏

https://zybuluo.com/ysner/note/1233363

题面

有一个长度为\(N\)的数组,每个格子颜色为黑或白。两人轮流操作。每次操作选择一个白格,假设它的下标为\(x\)。接着,选择一个大小在\(1-n/x\)之间的整数\(k\),然后将下标为\(x\)、\(2x\)、...、\(kx\)的格子都进行颜色翻转。不能操作的人输。问先手是否有必胜策略。

  • \(30pts\ n\leq20\)
  • \(50pts\ n\leq10^6\)
  • \(100pts\ n\leq10^9,w\leq100\)

解析

\(30pts\)算法

状态压缩+记忆化搜索

\(50pts\)算法

该问题很像翻硬币问题。

既然不能翻黑色格子,说明黑色格子的\(SG\)值对答案没有直接影响。

由性质\(SG(A\bigoplus B)=SG(A)\bigoplus SG(B)\),

可知整个游戏的\(SG\)值为所有可行操作的异或和,即所有白格的\(SG\)值异或和。

求\(SG\)值,就是对 所有后继状态(操作后状态)的\(SG\)值 的异或和取\(mex\)。

再应用一下上面那个性质,可得一个递推式

\[SG(x)=mex_{1<i\leq(n/x)}(\bigoplus_{t=2}^iSG(t*x))\]

模拟一发即可。

然而我因没注意到存在\(SG(x)>x\)和一定有\(SG(x)>0\)而\(WA\)得怀疑人生。。。

复杂度为\(O(nlogn)\)。

const int mod=1e9+7,N=1e7+100;
int n,q,w,SG[N],ans,viss[N];
il void getSG(re int x)
{
  re int t=1,tot=0;
  viss[0]=x;
  while(233)
    {
      ++t;
      if(x*t>n) break;
      viss[SG[x*t]^tot]=x;
      tot^=SG[x*t];
    }
  re int tmp=0;while(viss[tmp]==x) ++tmp;
  SG[x]=tmp;
}
int main()
{
  n=gi();q=gi();
  fq(i,n,1) getSG(i);
  while(q--)
  {
      ans=0;
      w=gi();
      fp(i,1,w) ans^=SG[gi()];
      puts(ans?"Yes":"No");
    }
  return 0;
}

\(100pts\)算法

经过愉快地打\(SG\)函数表后,发现只要\(n/i=n/j\),则\(SG(i)=SG(j)\)。

于是把\(SG\)值相同的值合为一块来计算即可。

注意存\(SG\)值的技巧:分为两半。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int mod=1e9+7,N=1e6+100;
int n,q,w,SG[2][N],ans,blk,b[N],id,vis[N];
il ll gi()
{
   re ll x=0,t=1;
   re char ch=getchar();
   while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘)) ch=getchar();
   if(ch==‘-‘) t=-1,ch=getchar();
   while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-48,ch=getchar();
   return x*t;
}
il int getSG(re int x)
{
  x=n/(n/x);
  if(x<=blk) return SG[0][x];else return SG[1][n/x];
}
il void Pre()
{
    for(re int i=1;i<=n;i=n/(n/i)+1) b[++b[0]]=n/(n/i);
    fq(i,b[0],1)
    {
        re int x=b[i],now=0;++id;vis[0]=id;
        for(re int j=x+x;j<=n;)
        {
            re int t=(n/(n/j))/x*x,tmp=(t-j)/x+1;
            vis[now^getSG(j)]=id;
            if(tmp&1) now^=getSG(j);
            j=t+x;
        }
        re int tmp=0;while(vis[tmp]==id) ++tmp;
        if(x<=blk) SG[0][x]=tmp;else SG[1][n/x]=tmp;
    }
}
int main()
{
  n=gi();q=gi();blk=sqrt(n)+1;
  Pre();
  while(q--)
  {
      ans=0;w=gi();
      fp(i,1,w) ans^=getSG(gi());
      puts(ans?"Yes":"No");
    }
  return 0;
}

原文地址:https://www.cnblogs.com/yanshannan/p/9397083.html

时间: 2024-10-12 17:44:23

[HAOI2015]数组游戏的相关文章

【BZOJ 4035】 4035: [HAOI2015]数组游戏 (博弈)

4035: [HAOI2015]数组游戏 Time Limit: 15 Sec  Memory Limit: 32 MBSubmit: 181  Solved: 89 Description 有一个长度为N的数组,甲乙两人在上面进行这样一个游戏:首先,数组上有一些格子是白的,有一些是黑的.然 后两人轮流进行操作.每次操作选择一个白色的格子,假设它的下标为x.接着,选择一个大小在1~n/x之间的整数 k,然后将下标为x.2x.....kx的格子都进行颜色翻转.不能操作的人输.现在甲(先手)有一些询

[HAOI2015] 数组游戏 - 博弈论,SG函数

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

博弈论题表(好少~~~)

bzoj2017:[Usaco2009 Nov]硬币游戏 *用了一小点思想的傻逼dp(记忆化搜索)bzoj1188:[HNOI2007]分裂游戏 **很神奇的把游戏拆分为子游戏的方法bzoj1022:[SHOI2008]小约翰的游戏John *傻逼SJ定理题bzoj1982:[Spoj 2021]Moving Pebbles **思路不一般的并不是很难证的傻逼结论题bzoj2688:Green Hackenbush **切树模型的傻逼概率dp(外有特殊的飞行技巧-判0剪枝)bzoj2281:[S

专题总结(博弈论)

https://zybuluo.com/ysner/note/1232112 双人平等博弈(理论应用前提) 信息完全公开 双方轮流行动 面对同一局面,双方的决策集合相同 一般来说,规定不能操作者输 游戏局面不会成环,有限步之后游戏必定结束 \(N\)态与\(P\)态 首先把结束的局面置为\(P\)态 对于一个\(P\)态,找到所有能转移到它的状态,它们全部是\(N\)态 搜到一个状态时,它还没有被筛掉,就是\(P\)态 很多题目中, P 态之间不可直接转移. 一些性质 \(SG\)值异或和为\(

2018十二月刷题列表

Preface \(2018\)年的尾巴,不禁感慨自己这一年的蜕变只能用蜕变来形容了. 而且老叶说我们今年没的参加清北冬令营可以参加CCF在广州二中举办的冬令营,只要联赛\(390+\)就应该可以报. 想都不要想啊当然是要去的啦,可以跑到这么远的地方交流一下还可以逃过一月月考(\(2019.1.24\to2019.1.31\)) 瞬间感觉有了点实质性的东西刺激一下自己了,而且离\(ZJOI\),真的不远了... LIst Luogu P3704 [SDOI2017]数字表格 大力的套路反演,只不

传智播客C语言视频第二季(增加诸多C语言案例讲解,有效下载期为10.5-10.10关闭)

?? 卷 backup 的文件夹 PATH 列表卷序列号为 000000F4 D4A8:14B0J:.│  1.txt│  2.txt│  ├─1传智播客_尹成_C语言从菜鸟到高手_第一章C语言概述A│  ├─文档│  │      第1讲 C语言第一阶段.doc│  │      │  └─视频│          第1讲 C语言第一阶段.mp4│          ├─2传智播客_尹成_C语言从菜鸟到高手_第二章C语言跨平台HelloWorld-A│  ├─第10节 2.5.1-2.5.7C

足球大数据:引人发思的问题

注:本序列文章都是本人对<The Numbers Game>书(豆瓣链接http://book.douban.com/subject/12274063/)的章节的翻译. 水平有限,如发现有错,敬请指导. 不论什么转载须说明转自http://blog.csdn.net/lingerlanlan. 本文链接:http://blog.csdn.net/lingerlanlan/article/details/31463735 这是一个简单的问题,每当美国人谈论足球的时候.都会用一种困惑的语调把它提出

博弈论入门小结

感受到了被博弈论支配的恐惧-- 入门的话个人按顺序推荐几篇论文: <由感性认识到理性认识--透析一类搏弈游戏的解答过程>张一飞 <解析一类组合游戏>  王晓珂 <组合游戏概述-浅谈SG游戏的若干拓展及变形> 贾志豪 看完这三篇还是要有点时间的,然而博主很傻的倒着看完了,然后就成功地完成了入门到放弃,事倍功半-- 到现在为止博弈论做了7道题,感觉只是大致学了一点皮毛,以后肯定回去再做一些题目,然而Hz书店没有和博弈论有关的书,差评. 只能说博弈论是一个很奇妙的东西,并没有

YCB 的暑期计划

前言 YCB现在很弱(TAT) 暑假有一个月,赶快狂补一下. 大概的计划如下: 首先前期会以数据结构为主,毕竟代码能力太弱,涉及内容:线段树分治.二进制分组.KD-Tree. 等数据结构做到没有智商的时候加入一波数论,内容为 杜教筛.min_25筛. 然后中途小清新一下,做一些 组合博弈与构造题. 接着继续练代码能力,顺便学一些神奇的暴力:启发式合并.dsu on tree . 然后图论也忘的差不多了,就回过头去学点新东西,大概会有spfa判负环.0/1分数规划.差分约束. 估计这个时候也没有什