Description

Transmission Gate

Solution

考虑Dp,设Dp[i] 表示当我们从前面跳跃到i时,他是必胜还是必败。

那么\(Dp[i] = Min(Dp[j], !(Dp[i + 1] = 1~ \&\&~(a[i] - 1)~mod~2 =0)), j \in [i + 1, i + m]\)

表示如果能跳的地方是必败态, 那么我们就跳跃过去,这样对方执子时一定是必败的

如果后面全都是必胜态,那么我们只有当A[i] 为奇数时, 才能强迫对方走到必胜态。这是O(n)的

考虑维护一个区间上的函数,函数F(x)表示一个状态(用0表示败,1表示胜,那么这个状态就有m位, 这个函数其实是数学中的映射)经过了这一个区间后会变成什么样子, 那么我们建立线段树来维护这个映射。当两个区间pushup的时候就直接枚举所有的状态X, 那么Front_F(Back_F(x)) 就是x所对应的状态。

考虑修改, 如果是偶数, 我们直接跳过,因为它不会影响区间任何一个数的奇偶性。那么加一个奇数就是把这个区间整体奇偶性改变。 那么我们只要维护一个新的线段树。 其上的区间与当前区间一一对应,代表当前区间整体改变了奇偶性的值,那么只需要在修改之后交换就可以了。

整体复杂度\(O(2^m(n + q) log n)\)

Inspiration

在作博弈题目时,由于每个点都是必胜或者必败, 可以考虑把跳跃看成转移,状态就直接设跳跃到哪一步, 然后当前节点的特有的值是多少, 因为是轮流取数, 我们可以考虑奇偶性进行转移。

因为要对一个区间进行维护,而且状态数特别少\((2 ^ m)\), 所以可以直接枚举每个Dp状态,建立一个函数,然后利用函数嵌套快速转移, 类似这种嵌套转移的东西还有矩阵快速幂。

其实奇偶性的情况特别少, 像这样的"特别少"的情况还有二进制中的(0,1), 三进制中的(0, 1, 2),以及后5位的状态等,对于这种状态特别少的情况,我们可以算出每个状况改变之后对应的状态。然后在修改时直接转移。

Update 20181202: 其实这样很像动态DP。

坑: 听说有\(O(m(n + q)log n)\)的做法?

Code

  1. #include<bits/stdc++.h>
  2. #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
  3. #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
  4. #define clar(a, b) memset((a), (b), sizeof(a))
  5. #define debug(...) fprintf(stderr, __VA_ARGS__)
  6. typedef long long LL;
  7. typedef long double LD;
  8. int read() {
  9. char ch = getchar();
  10. int x = 0, flag = 1;
  11. for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
  12. for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
  13. return x * flag;
  14. }
  15. void write(int x) {
  16. if (x < 0) putchar('-'), x = -x;
  17. if (x >= 10) write(x / 10);
  18. putchar(x % 10 + 48);
  19. }
  20. typedef std :: vector<int> seq;
  21. const int Maxn = 2e5 + 9, Maxm = 6, MaxLen = 1 << Maxm;
  22. static int n, m, q, a[Maxn], allMask;
  23. seq inital(int val) {
  24. seq res(1 << m);
  25. rep (i, 0, (1 << m) - 1) {
  26. if (i != (1 << m) - 1 || !(val & 1)) res[i] = (i >> 1) + (1 << (m - 1));
  27. else res[i] = i >> 1;
  28. }
  29. return res;
  30. }
  31. seq produce(seq input, seq func) {
  32. seq res(1 << m);
  33. rep (i, 0, (1 << m) - 1) res[i] = func[input[i]];
  34. return res;
  35. }
  36. namespace SGMTtree {
  37. seq tree[Maxn << 2], xorBak[Maxn << 2]; int add[Maxn << 2];
  38. #define lc(rt) ((rt) << 1)
  39. #define rc(rt) ((rt) << 1 | 1)
  40. #define ls rt << 1, l, mid
  41. #define rs rt << 1 | 1, mid + 1, r
  42. void pushup(int rt) {
  43. tree[rt] = produce(tree[rc(rt)], tree[lc(rt)]);
  44. xorBak[rt] = produce(xorBak[rc(rt)], xorBak[lc(rt)]);
  45. }
  46. void pushdown(int rt) {
  47. if (add[rt]) {
  48. add[lc(rt)] ^= 1; std :: swap(xorBak[lc(rt)], tree[lc(rt)]);
  49. add[rc(rt)] ^= 1; std :: swap(xorBak[rc(rt)], tree[rc(rt)]);
  50. add[rt] = 0;
  51. }
  52. }
  53. void build(int rt, int l, int r) {
  54. if (l == r) {
  55. tree[rt] = inital(a[l]), xorBak[rt] = inital(a[l] ^ 1);
  56. return ;
  57. }
  58. int mid = (l + r) >> 1;
  59. build(ls), build(rs);
  60. pushup(rt);
  61. }
  62. void modify(int rt, int l, int r, int p, int q) {
  63. if (p <= l && r <= q) {
  64. add[rt] ^= 1; std :: swap(tree[rt], xorBak[rt]);
  65. return ;
  66. }
  67. int mid = (l + r) >> 1; pushdown(rt);
  68. if (q <= mid) modify(ls, p, q);
  69. else if (p >= mid + 1) modify(rs, p, q);
  70. else modify(ls, p, q), modify(rs, p, q);
  71. pushup(rt);
  72. }
  73. seq query(int rt, int l, int r, int p, int q) {
  74. if (p <= l && r <= q) return tree[rt];
  75. int mid = (l + r) >> 1; pushdown(rt);
  76. if (q <= mid) return query(ls, p, q);
  77. else if (p >= mid + 1) return query(rs, p, q);
  78. else return produce(query(rs, p, q), query(ls, p, q));
  79. }
  80. #undef lc
  81. #undef rc
  82. #undef ls
  83. #undef rs
  84. }
  85. void init() {
  86. n = read(), m = read(), q = read();
  87. rep (i, 1, n) a[i] = read();
  88. allMask = (1 << m) - 1, SGMTtree :: build(1, 1, n);
  89. }
  90. void solve() {
  91. rep (i, 1, q) {
  92. int opt = read();
  93. if (opt == 1) {
  94. int l = read(), r = read(), v = read();
  95. if (v & 1) SGMTtree :: modify(1, 1, n, l, r);
  96. }
  97. if (opt == 2) {
  98. int l = read(), r = read();
  99. seq ans = SGMTtree :: query(1, 1, n, l, r);
  100. printf("%d\n", 1 + (((ans[(1 << m) - 1] >> (m - 1)) & 1) ^ 1));
  101. }
  102. }
  103. }
  104. int main() {
  105. init();
  106. solve();
  107. #ifdef Qrsikno
  108. debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
  109. #endif
  110. return 0;
  111. }

[CF1076G] Array Game的更多相关文章

  1. javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈

    Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...

  2. ES5对Array增强的9个API

    为了更方便的对Array进行操作,ES5规范在Array的原型上新增了9个方法,分别是forEach.filter.map.reduce.reduceRight.some.every.indexOf ...

  3. JavaScript Array对象

    介绍Js的Array 数组对象. 目录 1. 介绍:介绍 Array 数组对象的说明.定义方式以及属性. 2. 实例方法:介绍 Array 对象的实例方法:concat.every.filter.fo ...

  4. 了解PHP中的Array数组和foreach

    1. 了解数组 PHP 中的数组实际上是一个有序映射.映射是一种把 values 关联到 keys 的类型.详细的解释可参见:PHP.net中的Array数组    . 2.例子:一般的数组 这里,我 ...

  5. 关于面试题 Array.indexof() 方法的实现及思考

    这是我在面试大公司时碰到的一个笔试题,当时自己云里雾里的胡写了一番,回头也曾思考过,最终没实现也就不了了之了. 昨天看到有网友说面试中也碰到过这个问题,我就重新思考了这个问题的实现方法. 对于想进大公 ...

  6. javascript之活灵活现的Array

    前言 就如同标题一样,这篇文章将会灵活的运行Array对象的一些方法来实现看上去较复杂的应用. 大家都知道Array实例有这四个方法:push.pop.shift.unshift.大家也都知道 pus ...

  7. 5.2 Array类型的方法汇总

    所有对象都具有toString(),toLocaleString(),valueOf()方法. 1.数组转化为字符串 toString(),toLocaleString() ,数组调用这些方法,则返回 ...

  8. OpenGL ES: Array Texture初体验

    [TOC] Array Texture这个东西的意思是,一个纹理对象,可以存储不止一张图片信息,就是说是是一个数组,每个元素都是一张图片.这样免了频繁地去切换当前需要bind的纹理,而且可以节省系统资 ...

  9. Merge Sorted Array

    Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note:Yo ...

随机推荐

  1. ssh 执行多条命令包含awk的用法

    格式:ssh user@ip command 单条命令:ssh user@ip command1 多条命令:ssh user@ip "command1;command2" 不加双引 ...

  2. linux 中断机制浅析

    一.中断相关结构体 1.irq_desc中断描述符 struct irq_desc { #ifdef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED struct irq_ ...

  3. Could not find leader nimbus

    运行storm ui, 然后访问storm ui 的网页的时候,死活跑不起来.后面,根据下面这篇文章的说法, 停止zookeeper 之后,删掉zookeeper 上面的storm 节点, 然后再重启 ...

  4. ITIL的考核管理体系

    是的,我们ITIL的考核管理体系,大概是从几个方面进行考核的.阿里巴巴作为一个上市公司,是全球的B2B电子商务的领先者,那么作为我们的运维部,保证完整的可用性是首当其冲的.我们的ITIL考核体系里面, ...

  5. android 多进程 Binder AIDL Service

    本文參考http://blog.csdn.net/saintswordsman/article/details/5130947 android的多进程是通过Binder来实现的,一个类,继承了Bind ...

  6. ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则

    ASP.NET MVC 学习笔记-7.自定义配置信息   ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...

  7. oracle官方文档_查看初始化參数(举例)

    原创作品,出自 "深蓝的blog" 博客.深蓝的blog:http://blog.csdn.net/huangyanlong/article/details/46864217 记录 ...

  8. 在云服务器 ECS Linux CentOS 7 下重启服务不再通过 service 操作,而是通过 systemctl 操作

    在云服务器 ECS Linux CentOS 7 下重启服务不再通过 service  操作,而是通过 systemctl 操作. 操作说明如下: 1. 查看 sshd 服务是否启动: 看到上述信息就 ...

  9. Cocos从入门到精通--《创建第一个项目:HelloWorld》

    上节课我们解说了cocos2-x v3.7版本号的下载安装,也展示了使用CocosStudio编译不同平台运行程序的方法,大家是不是对新版本号的Cocos引擎充满期待?今天我们就创建一个project ...

  10. Library Project里面使用Case语句判断R.id值报错。case expressions must be constant expressions

    原文地址:http://blog.csdn.net/wchinaw/article/details/7325641 在一般的Android项目里R里面的资源声明看起来是这样的: public stat ...