Stone
Alice 和 Bob 在玩取石子的游戏。
他们共有 \(N\) 堆石子,第 \(i\) 堆石子有 \(a_{i}\) 个石子。
Alice 和 Bob 轮流取石子, Alice 先取,每一次取石子,当前取石子的人可以任选一堆还没有被取完的石子,从中取出至少 \(1\) 个,至多 \(x\) 个石子。
如果当前取石子的人没有石子堆可选,那么他(她)就输掉了游戏。
他们想知道,如果 Alice 和 Bob 都用最优策略玩游戏的话,谁会胜利。
由于 Alice 和 Bob 还没商量好 \(x\) 取多少,所以对于每个 \(1\) 到 \(N\) 之间的 \(x\),你都需要告诉他们谁将取得胜利。
对于 \(20\%\) 的数据, \(N\leqslant 8\)
对于 \(50\%\) 的数据, \(N\leqslant 5\times 10^3\)
对于 \(100\%\) 的数据, \(1\leqslant N\leqslant 5\times 10^5,1\leqslant a_{i}\leqslant N\)
首先,当\(a_i< x\)时,就是经典的取石子了
而只有一堆石子的时候,同样非常经典
所以不难得出当\(0={\LARGE\oplus}_{i=1}^Na_i\%(x+1)\)时为必败态
因为我们可以将所有\(a_i\)拆成\(v+(x+1)t\),使得先手无论如何操作,后手总能使之等效于模数的\(Nim\)游戏
这样就变成了计算所有数模某个数的异或和
我们设\(f_{i,j}\)表示值域区间在\([i,i+2^j)\)内的元素减去\(i\)后的异或和
\(g_{i,j}\)表示值域区间在\([i,i+2^j)\)内的元素的元素奇偶性
不难得到\(f_{i,j}=f_{i,j-1}\oplus f_{i+2^{j-1},j-1}\oplus(g_{i+2^{j-1},j-1}*2^{j-1})\)
这样就可以如同\(ST\)表地查询了
时间复杂度\(O(n\log^2n)\)
#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
T t=0;
char k;
bool vis=0;
do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
# define ll long long
int a[500005],s,v[20][500005],h[20][500005],Log2[500005];
int query(int l,int r){
int t=0,g=0;
for(int i;l<=r;)
if(i=Log2[r-l+1],l+(1<<i)-1<=r)
t^=v[i][l]|(h[i][l]*g),l+=1<<i,g|=1<<i;
return t;
}
char pr[3000005],*Sta=pr;
int main(){
fre("stone");
s=read;
for(int i=1;i<=s;++i)h[0][read]^=1;
for(int i=2;i<=s+1;++i)Log2[i]=Log2[i>>1]+1;
for(int i=0;(1<<i+1)<=s+1;++i)
for(int j=0;j+(1<<i+1)-1<=s;++j)
h[i+1][j]=h[i][j]^h[i][j+(1<<i)],
v[i+1][j]=v[i][j]^v[i][j+(1<<i)]^(h[i][j+(1<<i)]<<i);
for(int i=1;i<=s;++i){
int ans=0;
for(int j=0;j<=s;j+=i+1)
ans^=query(j,min(j+i,s));
if(ans){
memcpy(Sta,"Alice",5);
Sta[5]=" \n"[i==s];Sta+=6;
}else{
memcpy(Sta,"Bob",3);
Sta[3]=" \n"[i==s];Sta+=4;
}
}fwrite(pr,1,Sta-pr,stdout);
return 0;
}