题面

原题题面

转化方便版题意:

n

n

n 堆石子,第

i

i

i 堆有

c

i

[

1

,

m

]

c_i\in [1,m]

ci​∈[1,m] 个石子,有

q

q

q 次询问,每次询问给出

L

i

,

R

i

L_i,R_i

Li​,Ri​ ,先把

c

i

∉

[

L

i

,

R

i

]

c_i\not\in [L_i,R_i]

ci​​∈[Li​,Ri​] 的石堆都扔掉,然后把每堆石子减少

L

i

L_i

Li​ 个,最后用剩下的若干堆石子做

N

i

m

Nim

Nim 游戏,先手必胜输出

A

\tt A

A ,后手必胜输出

B

\tt B

B 。

1

n

,

m

,

q

2

1

0

5

1\leq n,m,q\leq2\cdot10^5

1≤n,m,q≤2⋅105.

题解

官方题解,是

O

(

N

N

log

N

)

O(N\sqrt{N\log N})

O(NNlogN

​) 的做法。

对每个询问暴力求解,是

O

(

N

2

)

O(N^2)

O(N2) 的。或者,如果记录每一种

c

i

c_i

ci​ 值的出现次数的话,也可以是

O

(

N

M

)

O(NM)

O(NM) 的。后者可以优化:

c

i

c_i

ci​ 的二进制表示有

18

\tt18

18 位,我们把前面九位和后面九位分开算,这样,分别就只有

2

9

=

512

2^9=512

29=512 种取值,也就是

M

\sqrt{M}

M

​ 种取值了,这就增加了暴力的可能性。同时,只管前九位和后九位都是能比较方便地处理加减法的,因此这样刚好是可行的,要是分成前六位、中六位、后六位就及其不好做了。

但是,处理后九位数字还是比较麻烦的。而且,这个时间复杂度也不优。

不如看看下面又易懂又好写还在时间复杂度上暴踩官解的做法。


真是妙蛙种子吃着妙脆角,妙进了米奇妙妙屋,妙到家了

真的就不能每一位分开来做了吗?

加减法固然会对二进制表示产生不好计量的影响,但是我们有这么一条很容易发现的结论:

  • A

    <

    2

    k

    A<2^k

    A<2k ,则

    A

    +

    2

    k

    =

    A

    x

    o

    r

    2

    k

    A+2^k=A~xor~2^k

    A+2k=A xor 2k

这种情况下,加法是等同于异或的!

那我们不妨就想个办法,能不能把减法变成加法,然后把要加的部分按位拆分开来,利用上面的结论一步一步异或进去呢?

有!那就是倍增。倍增可以把减法换成加法,而且不难发现,倍增刚好是从高位往低位考虑的,前面要加的数的 lowbit 一定比后面的数都大。

我们定义

f

[

i

]

[

j

]

f[i][j]

f[i][j] 为询问

L

=

i

,

R

=

i

+

2

j

1

L=i,R=i+2^j-1

L=i,R=i+2j−1 时的答案,不难发现

f

[

i

]

[

0

]

=

0

f[i][0]=0

f[i][0]=0。

计算

f

[

i

]

[

j

]

f[i][j]

f[i][j] 的时候,先异或上

f

[

i

]

[

j

1

]

f[i][j-1]

f[i][j−1] ,然后由于

f

[

i

+

2

j

1

]

[

j

1

]

f[i+2^{j-1}][j-1]

f[i+2j−1][j−1] 中的每堆石子个数

<

2

j

1

< 2^{j-1}

<2j−1 ,我们把这些石堆加上

2

j

1

2^{j-1}

2j−1 时,等价于异或

2

j

1

2^{j-1}

2j−1,因此我们只需要再知道

[

i

+

2

j

1

,

i

+

2

j

1

]

[i+2^{j-1},i+2^j-1]

[i+2j−1,i+2j−1] 区间之内石堆的个数,就可以转移了。令

c

t

[

i

]

[

j

]

ct[i][j]

ct[i][j] 表示

c

i

[

i

,

i

+

2

j

1

]

c_i\in[i,i+2^j-1]

ci​∈[i,i+2j−1] 的石堆的个数,则:

f

[

i

]

[

j

]

=

f

[

i

]

[

j

1

]

x

o

r

f

[

i

+

2

j

1

]

[

j

1

]

x

o

r

(

2

j

1

(

c

t

[

i

+

2

j

1

]

[

j

1

]

%

2

)

)

c

t

[

i

]

[

j

]

=

c

t

[

i

]

[

j

1

]

+

c

t

[

i

+

2

j

1

]

[

j

1

]

f[i][j]=f[i][j-1]~{\tt xor}~f[i+2^{j-1}][j-1]~{\tt xor}~\Big( 2^{j-1}\cdot(ct[i+2^{j-1}][j-1]\,\%\,2) \Big)\\ ct[i][j]=ct[i][j-1]+ct[i+2^{j-1}][j-1]

f[i][j]=f[i][j−1] xor f[i+2j−1][j−1] xor (2j−1⋅(ct[i+2j−1][j−1]%2))ct[i][j]=ct[i][j−1]+ct[i+2j−1][j−1]

询问的时候,类似的。由于是倍增,每次访问到的

f

[

i

]

[

j

]

f[i][j]

f[i][j] 的

j

j

j 都会变小,也就是说它所代表的这个区间内的石堆

c

i

c_i

ci​ 都小于先前的

2

j

2^j

2j ,都可以把加法换成异或,再通过

c

t

[

i

]

[

j

]

ct[i][j]

ct[i][j] 补到

f

[

i

]

[

j

]

f[i][j]

f[i][j] 中。

代码也很好理解,基本是标准的预处理倍增。时间复杂度只有

O

(

N

log

N

)

O(N\log N)

O(NlogN) 。

CODE

比解说还短的倍增代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
int n,m,i,j,s,o,k;
int c[MAXN],dp[MAXN][20],ct[MAXN][20];
int main() {
// Input
n = read();m = read();
for(int i = 1;i <= n;i ++)
c[i] = read(),ct[c[i]][0] ++; // Init
for(int i = m;i > 0;i --) {
for(int j = 1;i+(1<<j)-1 <= m;j ++) {
ct[i][j] = ct[i][j-1] + ct[i+(1<<(j-1))][j-1];
dp[i][j] = dp[i][j-1] ^ dp[i+(1<<(j-1))][j-1] ^ ((ct[i+(1<<(j-1))][j-1] & 1) ? (1<<(j-1)):0);
}
} // Query
int q = read();
while(q --) {
s = read();o = read();
int xr = 0,as = 0;
for(int j = 18;j >= 0;j --) {
if(s+(1<<j)-1 <= o) {
as ^= dp[s][j]^((ct[s][j] & 1) ? xr:0);
xr ^= (1<<j); s += (1<<j);
}
}
printf(as ? "A":"B");
}
return 0;
}

CF1511G Chips on a Board (倍增)的更多相关文章

  1. Codeforces 1511G - Chips on a Board(01trie/倍增)

    Codeforces 题面传送门 & 洛谷题面传送门 一道名副其实的 hot tea 首先显然可以发现这俩人在玩 Nim 游戏,因此对于一个 \(c_i\in[l,r]\) 其 SG 值就是 ...

  2. Architecture of Device I/O Drivers, Device Driver Design

    http://www.kalinskyassociates.com/Wpaper4.html Architecture of Device I/O Drivers Many embedded syst ...

  3. ARM JTAG 信号 RTCK 应该如何处理?

    用户在调试内嵌可综合内核的 CPU 如 ARM7TDMI-S 时,需要通过打开仿真器的自适应时钟功能. 此时,ARM仿真器根据 RTCK 时钟信号的频率,产生可用于 CPU 内核当前时钟主频的最快的 ...

  4. Implementation of Serial Wire JTAG flash programming in ARM Cortex M3 Processors

    Implementation of Serial Wire JTAG flash programming in ARM Cortex M3 Processors The goal of the pro ...

  5. CF1511G-Chips on a Board【倍增】

    正题 题目链接:https://www.luogu.com.cn/problem/CF1511G 题目大意 给出\(n*m\)的棋盘上每一行有一个棋子,双方轮流操作可以把一个棋子向左移动若干步(不能不 ...

  6. Codeforces Round #194 (Div. 2) D. Chips

    D. Chips time limit per test:1 second memory limit per test:256 megabytes input:standard input outpu ...

  7. ACM-ICPC Beijing 2016 Genius ACM(倍增+二分)

    描述 给定一个整数 M,对于任意一个整数集合 S,定义“校验值”如下: 从集合 S 中取出 M 对数(即 2∗M 个数,不能重复使用集合中的数,如果 S 中的整 数不够 M 对,则取到不能取为止),使 ...

  8. CH0601 Genius ACM【倍增】【归并排序】

    0601 Genius ACM 0x00「基本算法」例题 描述 给定一个整数 M,对于任意一个整数集合 S,定义“校验值”如下: 从集合 S 中取出 M 对数(即 2∗M 个数,不能重复使用集合中的数 ...

  9. Codeforces Round #194 (Div. 1) B. Chips 水题

    B. Chips Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/333/problem/B D ...

随机推荐

  1. ExtJS 布局-Border 布局(Border layout)

    更新记录: 2022年6月11日 发布. 2022年6月1日 开始. 1.说明 边框布局允许根据区域(如中心.北部.南部.西部和东部)指定子部件的位置.还可以调整子组件的大小和折叠. 2.设置布局方法 ...

  2. Python Excel 操作

    1.Excel Code import os import time import re import win32com.client def dealpath(pathname='') -> ...

  3. RPA-UiPath视频教程2

    UiPath参数的介绍和使用 https://www.bilibili.com/video/av83343849 UiPath第一个案例HelloWorld https://www.bilibili. ...

  4. sql-DQL-多表联查

    多表查询 笛卡尔积 左表的每条数据和右表的每条数据组合,这种效果称为笛卡尔乘积 select * from emp, dept; 笛卡尔积引入了很多无用的数据,要完成多表查询,需要设置过滤条件来消除无 ...

  5. python 常用的数据类型

    常用的数据类型 整数型 -> int 可以表示正数.负数.0 整数的不同进制的表示方法 十进制->默认的进制,无需特殊表示 二进制->以0b开头 八进制->以0o开头 十六进制 ...

  6. 强化学习-学习笔记7 | Sarsa算法原理与推导

    Sarsa算法 是 TD算法的一种,之前没有严谨推导过 TD 算法,这一篇就来从数学的角度推导一下 Sarsa 算法.注意,这部分属于 TD算法的延申. 7. Sarsa算法 7.1 推导 TD ta ...

  7. 异常注意事项_多异常的捕获处理和异常注意事项_finally有return语句

    异常注意事项_多异常的捕获处理 多个异常使用捕获又该如何处理呢? 1. 多个异常分别处理 2. 多个异常一次捕获,多次处理 3. 多个异常一次捕获一次处理 public class Demo01Exc ...

  8. springboot中的任务处理

    springboot中的任务处理 一.异步任务 在开发中有时用户提交的数据,后台需要一定时间才能做出响应,此时用户在前台也不能在等待中,此时就应该先开启异步请求处理,利用多线程,先给前台反馈,后台另一 ...

  9. Vue 路由懒加载, VueRouter一步完成Vue的路由懒加载 一行代码搞定懒加载

    Vue Router路由配置中的component里面配置即可 1 // 路由懒加载的方式加载组件 2 3 component: () => import('@/views/Detail'), ...

  10. Java中修饰符的分类及用法

    访问权限修饰符: public 修饰class,方法,变量: 所修饰类的名字必须与文件名相同,文件中最多能有一个pulic修饰的类. private class不可用,方法,变量可以用: 只限于本类成 ...