前言
这 (D) 不比 (C) 好写得多?
题目
题目大意:
( t Jaina) 和 ( t Sylvanas) 在玩游戏,战场上有 (2N) 个整数 (A_i),她们一共玩 (N) 轮游戏,每轮游戏的进程是这样的:
可爱的 ( t Jaina) 先手,选择一个数,记为 (x),然后 ( t Sylvanas) 选择另外一个数,记为 (y),然后擦掉这两个数,将 (x oplus y) 记在小本本上。
我们定义最后小本本上的最大的数为她们的得分,可爱的 ( t Jaina) 想最大化这个得分,而酷酷的 ( t Sylvanas) 却想最小化这个得分。请问在最优策略下,最终得分是多少?
(1le Nle 2 imes10^5;0le A_i<2^{30}.)
讲解
很显然这是个假博弈论,我们假设 ( t Sylvanas) 一开始就想好了最优策略,将每两个数提前配好对,无论 ( t Jaina) 怎么选, ( t Sylvanas) 都可以选择与其配对的数,以达到她的最优策略。
所以我们直接最小化这个得分就好了。
接下来就是套路了,我们将所有数按二进制拆分,从高位到低位贪心处理。
显然,对于某一位,如果有偶数个 (1),那么将 (0) 和 (1) 分开,即类似于分治的思想,再次进行此操作。
否则,一定会有 (0) 和 (1) 互相配对的情况,这个时候用字典树找最小值即可。
时间复杂度 (O(N imes log_2A).)
代码
//12252024832524
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 400005;
const int INF = (1ll << 30) - 1;
int n;
int a[MAXN],ans;
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
int b[MAXN],cao = -1;
struct node
{
int l,r,now;
node(){}
node(int l1,int r1,int now1){
l = l1;
r = r1;
now = now1;
}
};
queue<node> q;
int tot;
struct Trie
{
int ch[2];
}t[MAXN * 30];
void solve(int l,int r,int now)
{
if(now < 0 || l > r || now < cao) return;
int L = l,R = r;
for(int i = l;i <= r;++ i)
if((a[i] >> now) & 1) b[R--] = a[i];
else b[L++] = a[i];
for(int i = l;i <= r;++ i) a[i] = b[i];
if(!((L-l)&1)) {q.push(node(l,L-1,now-1)),q.push(node(L,r,now-1));return;}
cao = now;
int MIN = INF;
for(int i = L;i <= r;++ i)
{
int now = 0;
for(int j = 29;j >= 0;-- j)
{
int to = a[i] >> j & 1;
if(!t[now].ch[to]) t[now].ch[to] = ++tot;
now = t[now].ch[to];
}
}
for(int i = l;i < L;++ i)
{
int now = 0,val = 0;
for(int j = 29;j >= 0;-- j)
{
int to = a[i] >> j & 1;
if(t[now].ch[to]) now = t[now].ch[to];
else now = t[now].ch[to^1],val |= 1 << j;
}
MIN = Min(MIN,val);
}
ans = Max(MIN,ans);
for(int i = 0;i <= tot;++ i)
t[i].ch[0] = t[i].ch[1] = 0;
tot = 0;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read() << 1;
for(int i = 1;i <= n;++ i) a[i] = Read();
q.push(node(1,n,29));
while(!q.empty())
{
node t = q.front(); q.pop();
solve(t.l,t.r,t.now);
}
Put(ans);
return 0;
}