[ARC122D] XOR Game

前言

\(D\) 不比 \(C\) 好写得多?

题目

AtCoder

题目大意:

\(\tt Jaina\)\(\tt Sylvanas\) 在玩游戏,战场上有 \(2N\) 个整数 \(A_i\),她们一共玩 \(N\) 轮游戏,每轮游戏的进程是这样的:

可爱的 \(\tt Jaina\) 先手,选择一个数,记为 \(x\),然后 \(\tt Sylvanas\) 选择另外一个数,记为 \(y\),然后擦掉这两个数,将 \(x \oplus y\) 记在小本本上。

我们定义最后小本本上的最大的数为她们的得分,可爱的 \(\tt Jaina\) 想最大化这个得分,而酷酷的 \(\tt Sylvanas\) 却想最小化这个得分。请问在最优策略下,最终得分是多少?

\(1\le N\le 2\times10^5;0\le A_i<2^{30}.\)

讲解

很显然这是个假博弈论,我们假设 \(\tt Sylvanas\) 一开始就想好了最优策略,将每两个数提前配好对,无论 \(\tt Jaina\) 怎么选, \(\tt Sylvanas\) 都可以选择与其配对的数,以达到她的最优策略。

所以我们直接最小化这个得分就好了。

接下来就是套路了,我们将所有数按二进制拆分,从高位到低位贪心处理。

显然,对于某一位,如果有偶数个 \(1\),那么将 \(0\)\(1\) 分开,即类似于分治的思想,再次进行此操作。

否则,一定会有 \(0\)\(1\) 互相配对的情况,这个时候用字典树找最小值即可。

时间复杂度 \(O(N\times \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;
}
posted @ 2021-06-13 15:12  皮皮刘  阅读(67)  评论(0编辑  收藏  举报