[海军国际项目办公室]石子游戏
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[海军国际项目办公室]石子游戏相关的知识,希望对你有一定的参考价值。
石子游戏
题解
5
×
1
0
5
5\\times10^5
5×105的范围
O
(
n
log
2
n
)
O\\left(n\\log^2\\,n\\right)
O(nlog2n)就离谱,还只开
1
s
1s
1s。
看到这道题,我们应该很容易联想到
N
i
m
Nim
Nim游戏的方法,我们可以通过
s
g
sg
sg函数来得到答案。
我们定义
s
g
i
sg_{i}
sgi表示对于数量为
i
i
i的石子堆的
s
g
sg
sg函数值。
显然,
s
g
i
=
m
e
x
j
=
i
−
x
i
−
1
s
g
j
sg_{i}=mex_{j=i-x}^{i-1}sg_{j}
sgi=mexj=i−xi−1sgj,显然,答案当
x
o
r
i
=
1
n
s
g
a
i
xor_{i=1}^{n}sg_{a_{i}}
xori=1nsgai大于
0
0
0时是先手必胜的,否则是后手必胜的。
关于这个的证明可以自己去了解一下
N
i
m
Nim
Nim游戏。
而我们要求的是对于
x
=
1
,
2
,
.
.
.
,
n
x=1,2,...,n
x=1,2,...,n的所有情况的异或值。
我们考虑我们的
s
g
sg
sg函数与
x
x
x有什么关系。很容易发现,
s
g
i
=
(
i
m
o
d
(
x
+
1
)
)
sg_{i}=(i\\mod\\,(x+1))
sgi=(imod(x+1))。
所以,我们的答案应该是
x
o
r
i
=
1
n
(
a
i
m
o
d
(
x
+
1
)
)
xor_{i=1}^{n}(a_{i}\\mod\\,(x+1))
xori=1n(aimod(x+1))。
事实上只有出现奇数次的
a
i
a_{i}
ai会有贡献,我们记
a
i
a_{i}
ai出现次数的奇偶性为
c
n
t
a
i
cnt_{a_{i}}
cntai,那么答案应为
x
o
r
i
=
1
n
(
c
n
t
i
i
m
o
d
(
x
+
1
)
)
xor_{i=1}^{n}(cnt_{i}i\\mod\\, (x+1))
xori=1n(cntiimod(x+1))。
也就是说,我们每次只需要将出现奇数次的数模
x
+
1
x+1
x+1的异或和求来就行了。
而
x
x
x又会从
1
1
1到
n
n
n连续变化,考虑怎么求出这些答案。
它们都是模数在不断连续变化,我们很容易联想到Maximize GCD,通过调和级数来使我们的所有的枚举复杂度达到
log
n
\\log\\,n
logn。
但这样也就要求快速求出一个区间里的异或和,但这个区间内并非每个数都有贡献。
由于这是异或的转移,很容易从二进制位上找到方向,
[
0
,
1
,
.
.
.
,
2
j
−
1
−
1
]
[0,1,...,2^{j-1}-1]
[0,1,...,2j−1−1]与
[
2
j
−
1
,
2
j
−
1
+
1
,
.
.
.
,
2
j
]
[2^{j-1},2^{j-1}+1,...,2^{j}]
[2j−1,2j−1+1,...,2j]的区别仅在于
2
j
−
1
2^{j-1}
2j−1位上是
0
0
0还是
1
1
1。
所以我们可以通过倍增来快速求出答案。
我们定义
f
i
,
j
f_{i,j}
fi,j表示从
i
i
i开始,也就是
i
i
i的贡献为
1
1
1,往后延伸
2
j
2^j
2j位,贡献不断增加,最后总的异或和的大小。
很明显,
f
f
f的转移是与普通倍增的转移相似的,最多只需要判断后半部分的数的数量,如果是奇数就异或上
2
j
−
1
2^{j-1}
2j−1。
同样,对于每个数的查询我们也是一段一段跳着去查询这一段的异或和,每次跳到模
(
x
+
1
)
(x+1)
(x+1)为
1
1
1的位置,往后
x
x
x个的异或和。
同样地,这
x
x
x个也可以用上面的方法求出,我们从
2
log
x
2^{\\log\\,x}
2logx开始往下找,跳过去,后面跳的肯定包含我们前面跳的部分的二进制位,我们的步长是在逐渐缩小的,所以我们后面的会包含前面,同样通过奇偶性判断就行了。
每个
x
x
x会进行
⌈
n
x
⌉
\\lceil\\frac{n}{x}\\rceil
⌈xn⌉次倍增的操作,根据调和级数,最后进行的倍增操作次数是
n
ln
n
n\\ln\\,n
nlnn的。
时间复杂度 O ( n ln n log n ) O\\left(n\\ln\\,n\\log\\,n\\right) O(nlnnlogn)。
源码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 500005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int n1=50;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
char gc(){static char buf[5000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
#define getchar gc
char obuf[1<<22],*opt=obuf+(1<<22);
void pc(const int&ch){*--opt=ch;}
#define putchar pc
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s[海军国际项目办公室]矩阵