@description@

JOHNKRAM 和 C_SUNSHINE 在玩一个游戏。

游戏规则如下:有若干堆石子,游戏前选定一个正整数 p,JOHNKRAM 先手,两个人轮流操作。定义一次操作是选择某一堆石子,然后拿出其中的 p^k(k∈N) 个石子扔掉,不能操作者输。

C_SUNSHINE 表示判定谁能赢太简单了,于是他放了 n 堆石子,编号为 1∼n。

他每次把编号在某个区间内的石子堆加上若干个石子,或者询问以编号在某个区间内的石子堆进行游戏,是谁胜利。

JOHNKRAM 表示他不会做,于是他来向你求助。

input

第一行三个数 n, q, p,n 表示序列的长度,q 表示接下来操作的次数,p 的意义如题目描述中所说。

接下来一行 n 个数,第 i 个数表示初始时第 i 堆石子的石子数量。

接下来 q 行每行第一个数t表示操作类型,t=0 表示修改,t=1 表示询问。

对于一个修改操作,该行还会有三个数 l, r, x,表示把 [l…r] 的所有石子堆加上 x 个石子(博主注:x 为正数且属于 int 范围)。

对于一个询问操作,该行还会有两个数 l, r,表示询问以 [l…r] 的所有石子堆进行游戏是谁胜。

保证 1 <= n, q, p, 每堆石子的初始数量 <= 10^5。

output

对于每一个询问,如果 JOHNKRAM 胜利输出 1,否则输出 0。

sample input

10 9 3

2 6 2 5 8 7 4 3 4 1

1 1 10

0 5 7 15

1 1 3

0 3 9 11

1 3 7

0 4 5 53

0 1 2 26

1 6 10

1 4

sample output

0

0

0

1

0

@solution@

@part - 1@

通过 对sg函数打表 简单推导可得:

(1)当 p 为奇数时,sg函数循环节长度为 2,循环节为 01。即:

当 x % 2 == 0 时,sg[x] = 0。

当 x % 2 == 1 时,sg[x] = 1。

(2)当 p 为偶数时,sg函数循环节长度为 (p+1),循环节为 010101……01012。即:

当 x % (p+1) == p 时,sg[x] = 2。

当 (x % (p+1)) % 2 == 1 时,sg[x] = 1。

当 x % (p+1) != p 且 (x % (p+1)) % 2 == 0 时,sg[x] = 0。

简要(感性地)证明一下吧:

首先我们可以发现,当 x < p 时,只能从 sg[x-1] 到 sg[x],故一定形如 010101……

当 p 为奇数时,p^k 肯定也为奇数,即我们总是只能从偶数转移到奇数,奇数转移到偶数,故只能是 010101……

当 p 为偶数时,可以发现 p^k = (-1)^k (mod p+1),于是我们可以在 mod p+1 的意义下从 x+1 与 x-1 转移到 x。故当 x % (p+1) == p 时,sg[x] 只能等于 2。

于是可以得证。

@part - 2@

根据 sg 函数应用于博弈论的结论,我们必须在询问时求出区间 [l, r] 中 sg 函数的异或和才能判定胜负。

奇数很好办,写一个支持区间反转,统计区间中 1 的个数的线段树即可。

考虑偶数。我们需要在支持模意义下区间加操作时,至少可以询问一个区间内值等于 p 的个数(即 sg[x] = 2 的个数)。

我不知道线段树能不能搞。这显然是分块来搞。修改时整块加法标记,散块暴力重构;查询时整块通过加法标记寻找,散块暴力遍历。

再考虑求出一个区间内值为奇数的个数(即 sg[x] = 1 的个数)。考虑重构时储存值为奇数与值为偶数的两个有序数列,这样整块在加法标记下,新奇数序列必然是原奇数序列的某后缀接上原偶数序列的某前缀,或反过来原偶数序列的某后缀接上原奇数序列的某前缀。新偶数序列同理。

于是我们根据加法标记二分查找一下,就可以求出 sg[x] = 1 的个数了。

显然奇数也可以分块来搞,所以我们就可以不用写线段树了。

总复杂度 O(nsqrt(n)log n),有些卡但开了O2大概3s能过。

标算给出了一个 O(nsqrt(nlog n)) 的算法,不过太难写了。

大概就是在重构时充分利用原奇偶序列的有序性,归并两个有序数列可以在线性时间内完成,于是可以线性时间完成重构。然后再重新调整块的大小使询问与修改的复杂度平衡。

这个常数说不定还不如上面那个算法……

@accepted code@

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. #define lb lower_bound
  5. const int BLOCK = 320;
  6. const int MAXN = 100000;
  7. int le[MAXN/BLOCK + 5], ri[MAXN/BLOCK + 5], add[MAXN/BLOCK + 5], num[MAXN + 5];
  8. int arr[2][MAXN/BLOCK + 5][BLOCK + 5], siz[2][MAXN/BLOCK + 5];
  9. int n, q, p, bcnt;
  10. int a[MAXN + 5];
  11. void rebuild(int x) {
  12. siz[0][x] = siz[1][x] = 0;
  13. for(int i=le[x];i<=ri[x];i++)
  14. arr[a[i]&1][x][++siz[a[i]&1][x]] = a[i];
  15. sort(arr[0][x] + 1, arr[0][x] + siz[0][x] + 1);
  16. sort(arr[1][x] + 1, arr[1][x] + siz[1][x] + 1);
  17. }
  18. void build() {
  19. bcnt = (n-1)/BLOCK + 1;
  20. for(int i=0;i<n;i++) {
  21. if( i % BLOCK == 0 )
  22. le[i/BLOCK+1] = ri[i/BLOCK+1] = i;
  23. else ri[i/BLOCK+1]++;
  24. num[i] = i/BLOCK+1;
  25. }
  26. for(int i=1;i<=bcnt;i++)
  27. rebuild(i);
  28. }
  29. void pushdown(int x) {
  30. for(int i=le[x];i<=ri[x];i++)
  31. a[i] = (a[i] + add[x])%(p+1);
  32. add[x] = 0;
  33. }
  34. int fun(int x) {
  35. if( x == p ) return 2;
  36. else return (x&1);
  37. }
  38. int main() {
  39. freopen("right.in", "r", stdin);
  40. freopen("right.out", "w", stdout);
  41. scanf("%d%d%d", &n, &q, &p);
  42. if( p % 2 == 1 ) p = 1;
  43. for(int i=0;i<n;i++)
  44. scanf("%d", &a[i]), a[i] %= (p+1);
  45. build();
  46. for(int i=1;i<=q;i++) {
  47. int tp; scanf("%d", &tp);
  48. if( tp == 0 ) {
  49. int l, r, x; scanf("%d%d%d", &l, &r, &x), l--, r--, x %= (p+1);
  50. if( num[l] == num[r] ) {
  51. pushdown(num[l]);
  52. for(int i=l;i<=r;i++)
  53. a[i] = (a[i] + x)%(p+1);
  54. rebuild(num[l]);
  55. }
  56. else {
  57. for(int i=num[l]+1;i<=num[r]-1;i++)
  58. add[i] = (add[i] + x)%(p+1);
  59. pushdown(num[l]);
  60. for(int i=l;i<=ri[num[l]];i++)
  61. a[i] = (a[i] + x)%(p+1);
  62. rebuild(num[l]);
  63. pushdown(num[r]);
  64. for(int i=le[num[r]];i<=r;i++)
  65. a[i] = (a[i] + x)%(p+1);
  66. rebuild(num[r]);
  67. }
  68. }
  69. else {
  70. int l, r, ans = 0; scanf("%d%d", &l, &r), l--, r--;
  71. if( num[l] == num[r] ) {
  72. for(int i=l;i<=r;i++)
  73. ans ^= fun((a[i] + add[num[i]])%(p+1));
  74. }
  75. else {
  76. for(int i=l;i<=ri[num[l]];i++)
  77. ans ^= fun((a[i] + add[num[i]])%(p+1));
  78. for(int i=le[num[r]];i<=r;i++)
  79. ans ^= fun((a[i] + add[num[i]])%(p+1));
  80. for(int i=num[l]+1;i<=num[r]-1;i++) {
  81. int t1 = p-add[i];
  82. int x = upper_bound(arr[t1&1][i]+1, arr[t1&1][i]+siz[t1&1][i]+1, t1) - arr[t1&1][i];
  83. int y = lower_bound(arr[t1&1][i]+1, arr[t1&1][i]+siz[t1&1][i]+1, t1) - arr[t1&1][i];
  84. int z = upper_bound(arr[t1&1^1][i]+1, arr[t1&1^1][i]+siz[t1&1^1][i]+1, t1) - arr[t1&1^1][i];
  85. if( (x-y) & 1 ) ans ^= 2;
  86. if( p != 1 && ((z-1+siz[t1&1][i]-x+1) & 1) ) ans ^= 1;
  87. }
  88. }
  89. puts(ans ? "1" : "0");
  90. }
  91. }
  92. }
  93. /*
  94. 以下是打表用程序:
  95. #include<cstdio>
  96. const int MAXN = 100;
  97. int sg[MAXN + 5];
  98. bool tag[MAXN + 5];
  99. int main() {
  100. int p; scanf("%d",Q &p);
  101. sg[0] = 0;
  102. for(int i=1;i<=MAXN;i++) {
  103. for(int j=0;j<=MAXN;j++)
  104. tag[j] = false;
  105. tag[sg[i-1]] = true;
  106. if( p != 1 ) {
  107. int x = p;
  108. while( x <= i ) {
  109. tag[sg[i-x]] = true;
  110. x *= p;
  111. }
  112. }
  113. for(int j=0;;j++)
  114. if( !tag[j] ) {
  115. sg[i] = j;
  116. break;
  117. }
  118. }
  119. for(int i=0;i<=MAXN;i++)
  120. printf("%d : %d\n", i, sg[i]);
  121. }
  122. */

@details@

康复计划 - 9。

当我对博弈论一筹莫展时,旁边的 zxb 大佬小声地提醒我说:“打表”。突然就幡然醒悟了。

这场比赛的 T2 我还没写,因为我还没有理解随机状况下标算时间复杂度怎么来的。以后慢慢填坑(咕咕咕)。

@NOI模拟2017.06.30 - T3@ Right的更多相关文章

  1. @NOI模拟2017.06.30 - T1@ Left

    目录 @description@ @solution@ @accepted code@ @details@ @description@ JOHNKRAM 最近在研究排序网络,但他发现他不会制作比较器, ...

  2. @NOI模拟2017.07.02 - T1@ Attack

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 『新的风暴已经出现,怎么能够停滞不前』--你决定去攻击小怪兽的巢 ...

  3. 5.30 NOI 模拟

    $5.30\ NOI $模拟 高三大哥最后一次模拟考了,祝他们好运 \(T1\)装箱游戏 显然可以将四种字母之间的空缺当做状态枚举 那么这道题就很显然了 #include<bits/stdc++ ...

  4. 5.23 NOI 模拟

    $5.23\ NOI $模拟 \(T1\)简单的计算几何题 \(zjr:\)我当时没改,那么自己看题解吧 倒是有个简单的随机化方法(能获得\(72pts,\)正确性未知)\(:\) 随机两条切椭圆的平 ...

  5. 5.6 NOI模拟

    \(5.6\ NOI\)模拟 明天就母亲节了,给家里打了个电话(\(lj\ hsez\)断我电话的电,在宿舍打不了,只能用教练手机打了) 其实我不是很能看到自己的\(future,\)甚至看不到高三的 ...

  6. 5.4 NOI模拟

    \(5.4\ NOI\)模拟 \(T1\) 想到分讨,但是暴力输出一下方案之后有很多特别的情况要讨论,就弃了... 假设\(a\)是原序列,\(b\)是我们得到的序列 设\(i\)是最长公共前缀,\( ...

  7. hdu6034[模拟] 2017多校1

    /*hdu6034[模拟] 2017多校1*/ //暴力模拟26个26进制数即可, 要注意进位 #include<bits/stdc++.h> using namespace std; t ...

  8. 【2018.12.10】NOI模拟赛3

    题目 WZJ题解 大概就是全场就我写不过 $FFT$ 系列吧……自闭 T1 奶一口,下次再写不出这种 $NTT$ 裸题题目我就艹了自己 -_-||| 而且这跟我口胡的自创模拟题 $set1$ 的 $T ...

  9. 【NOI】2017 蚯蚓排队(BZOJ 4943,LOJ 2303) 模拟+hash

    [题目]#2303. 「NOI2017」蚯蚓排队 [题意]给定n条长度不超过6的蚯蚓,初始各自在一个队伍.m次操作:1.将i号蚯蚓和j号蚯蚓的队伍合并(保证i为队尾,j为队首).2.将i号蚯蚓和它后面 ...

随机推荐

  1. 洛谷P3459 [POI2007]MEG-Megalopolis [2017年6月计划 树上问题02]

    [POI2007]MEG-Megalopolis 题目描述 Byteotia has been eventually touched by globalisation, and so has Byte ...

  2. caffe 的docker安装过程及相关linux操作总结

    一.caffe 和 docker的安装编译 docker pull caffe镜像(注意使用docker安装省去安装CUDA和cudnn的安装.) 安装相关依赖包 安装opencv3(使用源码安装) ...

  3. Phpstrom学习笔记

    1.用*标识编辑过的文件 File - Editor – General - Editor Tabs 选中Mark modifyied tabs with asterisk

  4. web前端学习(三)css学习笔记部分(5)-- CSS动画--页面特效、HTML与CSS3简单页面效果实例

    CSS动画--页面特效部分内容目前仅仅观看了解内容,记录简单笔记,之后工作了进行内容的补充 7.  CSS动画--页面特效 7.1  2D.3D转换 7.1.1  通过CSS3转换,我们能够对元素进行 ...

  5. Hdu 1150

    Machine Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  6. NodeJS概述2-事件插件-简易爬虫

    事件 events 模块 原生事件写法 /* * 1. 事件分类 * DOM0级 事件 - on + eventType * DOM2级 事件 - 事件监听 * 2. 事件构成部分有哪些? dom.o ...

  7. DMSkin https://github.com/944095635/DMSkin

    与源码无关内容 1.如果你有XAML相关的外包需求,可以通过QQ或微信与我取得联系.(QQ:"944095635" 微信号:"qq944095635") 2.我 ...

  8. 数据库----ORACLE和MYSQL数据库简介

    一.什么是数据库? 数据库(Database---DB)按照组织.储存和管理数据的仓库.(理解以下三个概念)   数据(Data)用来描述事物的记录都可称数据,如文字音乐图像.   数据库系统(Dat ...

  9. linux下的OpenCV安装&学习笔记

    http://www.linuxdiyf.com/viewarticle.php?id=20731 (本想在fedora下安装编译的,但目前opencv官网.sourceforge等网站都无法访问下载 ...

  10. PHPCMS快速建站系列之添加单页模版

    单页模板命名:page_xxx.html 以page_开头 在模版所在目录的config.php中添加配置项 'page_xxx.html' => '单网页', 也可以不在config中配置,不 ...