[ARC122D]XOR Game
壹、题目描述 ¶
贰、题解 ¶
还是太弱了......明显递归子问题都没有发现。
我们考虑从高到低枚举每一位 \(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;
}
肆、关键的地方 ¶
有偶数的好数时,确实想到应该内部匹配,但是我想到不同位置的好数不同,不同位置的好数集有可能出现交而不包含的情况,所以我往颜色覆盖方向想了,并且一条路走到黑......但实际上我忽略了二进制下(也不只是二进制)最高位的支配性质较高位的好数一定是单独内部匹配,而肯定不会让它的好数集和好数集的补集中的数进行匹配。