石子游戏
题解
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=='-')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){putchar('\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,a[MAXN],cnt[MAXN],sum[MAXN],f[MAXN][22],ans,lg[MAXN],hig[MAXN];
signed main(){
freopen("stone.in","r",stdin);
freopen("stone.out","w",stdout);
read(n);for(reg int i=1;i<=n;i++)read(a[i]),cnt[a[i]]^=1;
for(reg int i=1;i<=n;i++)sum[i]=sum[i-1]+cnt[i];
for(reg int i=1;i<=n;i++)f[i][0]=cnt[i];
for(reg int i=2;i<=n;i++)lg[i]=lg[i>>1]+1,hig[i]=hig[i>>1]+1;
for(reg int j=1;j<=lg[n];j++)
for(reg int i=1;i<=n-(1<<j)+1;i++){
f[i][j]=f[i][j-1]^f[i+(1<<j-1)][j-1];
if(cnt[i+(1<<j)-1])f[i][j]^=(1<<j-1),f[i][j]^=(1<<j);
if(sum[i+(1<<j)-2]-sum[i+(1<<j-1)-1]&1)f[i][j]^=(1<<j-1);
}
for(reg int i=n;i>0;i--){
ans=0;
for(reg int j=1;j<=n;j+=(i+1)){
reg int tp=0,x=j,len=min(i,n-j+1);
for(reg int k=len;k;){
const int t=(1<<hig[k]);
if(sum[x+t-1]-sum[x-1]&1)ans^=tp;
ans^=f[x][hig[k]];tp^=t;x+=t;k^=t;
}
}
if(i==n)pc('\n');else pc(' ');
if(ans)pc('e'),pc('c'),pc('i'),pc('l'),pc('A');
else pc('b'),pc('o'),pc('B');
}
fwrite(opt,1,obuf+(1<<22)-opt,stdout);
return 0;
}