[ARC122D]XOR Game

壹、题目描述 ¶

传送门 to Atcoder.

贰、题解 ¶

还是太弱了......明显递归子问题都没有发现。

我们考虑从高到低枚举每一位 \(bit(bit\in[0,29])\),对于某个 \(bit\),我们称含有该位的数字为好的,剩下的为不好的。

  • 如果有偶数个,那么一定是好的数字内部匹配,不好的数字进行匹配,这变成了一个子问题 —— 考虑分而治之;
  • 如果有奇数个,必定有一个好的和一个不好的进行匹配,并且他们的异或值一定为最大值,那么这个问题就是 —— 从好的数字中选择一个,和所有不好的数字进行匹配,找到最小的异或值,很显然,一发 \(\rm Trie\) 树搞定;

复杂度 \(\mathcal O(n\log a)\).

叁、参考代码 ¶

#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;

// #define NDEBUG
#include<cassert>

namespace Elaina{
    #define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
    #define drep(i, l, r) for(int i=(l), i##_end_=(r); i>=i##_end_; --i)
    #define fi first
    #define se second
    #define mp(a, b) make_pair(a, b)
    #define Endl putchar('\n')
    #define mmset(a, b) memset(a, b, sizeof a)
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    template<class T>inline T fab(T x){ return x<0? -x: x; }
    template<class T>inline void getmin(T& x, const T rhs){ x=min(x, rhs); }
    template<class T>inline void getmax(T& x, const T rhs){ x=max(x, rhs); }
    template<class T>inline T readin(T x){
        x=0; int f=0; char c;
        while((c=getchar())<'0' || '9'<c) if(c=='-') f=1;
        for(x=(c^48); '0'<=(c=getchar()) && c<='9'; x=(x<<1)+(x<<3)+(c^48));
        return f? -x: x;
    }
    template<class T>inline void writc(T x, char s='\n'){
        static int fwri_sta[1005], fwri_ed=0;
        if(x<0) putchar('-'), x=-x;
        do fwri_sta[++fwri_ed]=x%10, x/=10; while(x);
        while(putchar(fwri_sta[fwri_ed--]^48), fwri_ed);
        putchar(s);
    }
}
using namespace Elaina;

const int maxn=2e5*2;
const int loga=30;
const int inf=0x3f3f3f3f;

int n, ans=-inf;

namespace trie{
    int tre[maxn*loga*10+5][2], ncnt;
    inline int apply(){
        ++ncnt;
        tre[ncnt][0]=tre[ncnt][1]=0;
        return ncnt;
    }
    inline void clear(){ ncnt=0; apply(); }
    inline void insert(int x){
        int now=1, to;
        drep(t, 29, 0){
            to=((x>>t)&1);
            if(!tre[now][to])
                tre[now][to]=apply();
            now=tre[now][to];
        }
    }
    inline int match(int x){
        int now=1, to, ret=0;
        drep(t, 29, 0){
            to=((x>>t)&1);
            if(tre[now][to]) now=tre[now][to];
            else now=tre[now][to^1], ret^=(1<<t);
        }
        return ret;
    }
}

int a[maxn+5];
int cur[maxn+5], res[maxn+5];
inline void solve(int l, int r, int t){
    // printf("When t == %d, [%d, %d] : \n", t, l, r);
    // rep(i, l, r) writc(a[i], ' '); Endl;
    if(t<0) return ans=max(ans, 0), void();
    int ccnt=0, rcnt=0;
    rep(i, l, r){
        if((a[i]>>t)&1) cur[++ccnt]=a[i];
        else res[++rcnt]=a[i];
    }
    rep(i, 1, ccnt) a[l+i-1]=cur[i];
    rep(i, 1, rcnt) a[l+ccnt+i-1]=res[i];
    if(!ccnt) return solve(l, r, t-1);
    else{
        if(ccnt&1){
            trie::clear();
            rep(i, l+ccnt, r) trie::insert(a[i]);
            int ret=inf;
            rep(i, l, l+ccnt-1)
                ret=min(ret, trie::match(a[i]));
            return ans=max(ans, ret), void();
        }
        else return solve(l, l+ccnt-1, t-1), solve(l+ccnt, r, t-1);
    }
}

signed main(){
    n=readin(1);
    rep(i, 1, n<<1) a[i]=readin(1);
    solve(1, n<<1, 29);
    writc(ans);
    return 0;
}

肆、关键的地方 ¶

有偶数的好数时,确实想到应该内部匹配,但是我想到不同位置的好数不同,不同位置的好数集有可能出现交而不包含的情况,所以我往颜色覆盖方向想了,并且一条路走到黑......但实际上我忽略了二进制下(也不只是二进制)最高位的支配性质较高位的好数一定是单独内部匹配,而肯定不会让它的好数集和好数集的补集中的数进行匹配。

posted @ 2021-06-13 14:42  Arextre  阅读(81)  评论(0编辑  收藏  举报