【题解】黑白 Nim (2019,5.23)
Description
Sample Input
3
2 0
2 0
2 1
Sample Output
A_1->0
A_2->0
A_3->0
A_3->(1,1)
Solution
考虑分成两堆的SG函数还是挺好写的。只要两个堆的SG值Xor起来就好了。
写完暴力打个表。
震惊!!! 居然有规律。
发现如果 \(x\) 是二的次幂那么 \(SG[x]=x-1\)
如果 \(x+1\) 是二的幂次那么 \(SG[x]=x+1\)
其他的 \(SG\) 都是本身。
然后我们求出所有的 \(SG\) 值的Xor和然后枚举第一下取那个堆。
然后变个式子。
我们想要求一个 \(x\) 使 \(ans\ xor \ a[i]\ xor\ x==0\)
那么我们直接用Xor的性质直接把 \(x\) 求出来,但是我们这样求出来的 \(x\) 是 \(SG\),所以我们得把 \(SG\) 值映射一下。做到 \(O(1)\) 。
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1e6+5;
int a[N],SG[N];
int col[N],f[N];
inline int lowbit(int x){
return x&(-x);
}
inline void GetSG(int id){
if(a[id]==0){
SG[id]=0;
return;
}
if(a[id]==1){
SG[id]=1;
return;
}
if(a[id]==2){
SG[id]=2;
return;
}
if(a[id]-lowbit(a[id])==0){
SG[id]=a[id]-1;
return;
}
if(a[id]+1-lowbit(a[id]+1)==0){
SG[id]=a[id]+1;
return;
}
SG[id]=a[id];
}
inline int calc(int x){
if(x==0) return 0;
if(x==1) return 1;
if(x==2) return 2;
if(x-lowbit(x)==0) return x-1;
if(x+1-lowbit(x+1)==0) return x+1;
return x;
}
inline void solve(){
for(int i=1;i<=N-5;++i)
SG[i]=calc(i),f[SG[i]]=i;
for(int i=1;i<=n;++i)
scanf("%d%d",&a[i],&col[i]);
int ans=0;
for(int i=1;i<=n;++i){
if(col[i]==0) ans^=a[i];
if(col[i]==1) ans^=SG[a[i]];
}
for(int i=1;i<=n;++i){
if(col[i]==0){
int x=(0^ans^a[i]);
if(x<a[i]) printf("A_%d->%d\n",i,x);
}
if(col[i]==1){
int x=(0^ans^SG[a[i]]);
if(f[x]<a[i]) printf("A_%d->%d\n",i,f[x]);
if((ans^SG[a[i]]^(SG[a[i]/2]^SG[a[i]-a[i]/2]))==0)
printf("A_%d->(%d,%d)\n",i,min(a[i]/2,a[i]-a[i]/2),max(a[i]/2,a[i]-a[i]/2));
}
}
}
int main(){
scanf("%d",&n);
solve();
return 0;
}