【题解】黑白 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;
}


posted @ 2019-05-23 16:22  章鱼那个哥  阅读(185)  评论(0编辑  收藏  举报