[CF1511G]Chips on a Board
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1511G]Chips on a Board相关的知识,希望对你有一定的参考价值。
Chips on a Board
题解
r
i
s
u
j
i
r
o
h
\\color{red}risujiroh
risujiroh的
n
2
n^2
n2竟然不能hack掉!!!
好吧,我们不谈
n
2
n^2
n2的做法,下面讲一下正解。
关于胜负的判断就是个简单的Nim游戏,我们任务相当于维护一个区间中数关于左边界差的异或和。
首先我们很容易联想到莫队,每次移动就相当于全局的
±
1
\\pm1
±1与添加/删除数。
我们考虑用
t
r
i
e
trie
trie树维护这些数的异或和,但很明显,如果我们直接正着做明显是会T掉的,考虑将
t
r
i
e
trie
trie树倒过来建。
每次
+
1
+1
+1操作相当于一直将右儿子与左儿子交换,并向左儿子传递下去,
−
1
-1
−1操作同理。
由于我们每次移动都要进行一次操作,并还有数的插入与删除,所以我们的时间复杂度成功达到了
O
(
n
n
l
o
g
n
)
O\\left( n\\sqrt{n}log\\,n\\right)
O(nnlogn)。
官方题解用了一个奇妙的
O
(
n
n
l
o
g
n
)
O\\left(n\\sqrt{nlog\\,n}\\right)
O(nnlogn)的根号分治算法,这里就不详细讲了。我们详细讲一种更好写的
O
(
n
l
o
g
n
)
O\\left(nlog\\,n\\right)
O(nlogn)的倍增做法。
我们很容易发现我们下传的操作当这一位已经是最高位,没有其他儿子时是不会发生的。所以我们只要使得我们每次增加的数都是最大数就不需要考虑下传了,答案的改变至于数的个数有关。
我们定义
s
u
m
i
,
j
sum_{i,j}
sumi,j表示
[
i
,
i
+
2
j
)
[i,i+2^j)
[i,i+2j)的区间中的数减去
i
i
i时的异或和,
n
u
m
i
,
j
num_{i,j}
numi,j表示
[
i
,
i
+
2
j
)
[i,i+2^j)
[i,i+2j)中数的个数。
很明显,
[
i
,
i
+
2
j
)
[i,i+2^j)
[i,i+2j)中的数相对于
i
i
i都是不会超过
2
j
2^j
2j的,所以当我们扩大
2
j
2^j
2j时,如果
n
u
m
i
,
j
num_{i,j}
numi,j为奇数答案就会增加
2
j
2^j
2j,所以我们只需要记录下
n
u
m
i
,
j
num_{i,j}
numi,j的奇偶即可。
有倍增式
s
u
m
i
,
j
=
s
u
m
i
,
j
−
1
⊗
s
u
m
i
+
2
j
−
1
,
j
−
1
⊗
(
2
n
u
m
i
+
2
j
−
1
,
j
−
1
)
j
−
1
sum_{i,j}=sum_{i,j-1}\\otimes sum_{i+2^{j-1},j-1}\\otimes (2num_{i+2^{j-1},j-1})^{j-1}
sumi,j=sumi,j−1⊗sumi+2j−1,j−1⊗(2numi+2j−1,j−1)j−1。
对于每个询问,我们只需要从右端点从小往大递增即可。
时间复杂度 O ( n l o g n ) O\\left(nlog\\,n\\right) O(nlogn)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x7f7f7f7f7f7f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int qkpow(int a,int s){int t=1;while(s){if(s&1)t=1ll*a*t%mo;a=1ll*a*a%mo;s>>=1;}return t;}
int n,m,c[MAXN],q,sum[MAXN][22],num[MAXN][22],lg[MAXN];
char ans[MAXN];
signed main(){
read(n);read(m);for(reg int i=1;i<=n;++i)read(c[i]),num[c[i]][0]^=1;
read(q);for(reg int i=2;i<=m;++i)lg[i]=lg[i>>1]+1;
for(reg int j=1;j<=lg[m];++j)
for(reg int i=1,k=(1<<j-1);i<=m-(1<<j)+1;++i)
num[i][j]=num[i][j-1]^num[i+k][j-1],
sum[i][j]=sum[i][j-1]^sum[i+k][j-1]^(num[i+k][j-1]<<j-1);
for(reg int i=1;i<=q;++i){
int l,r,res=0;read(l);read(r);int id=r+1,x=0;
for(reg int k=0;k<=lg[r-l+1];++k)if(r-l+1&(1<<k))
id-=(1<<k),res^=sum[id][k]^(x<<k),x^=num[id][k];
ans[i]=res?'A':'B';
}
printf("%s\\n",ans+1);
return 0;
}
谢谢
以上是关于[CF1511G]Chips on a Board的主要内容,如果未能解决你的问题,请参考以下文章
Calculates the closest direction to a specified point on the board.
ProjectEuler237 Tours on a 4 x n playing board
解决LicheeRV 86 Panel在tina2.0配置lcd GPIO引脚及colorbar闪屏的问题