zoukankan      html  css  js  c++  java
  • [ARC122D] XOR Game

    前言

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

    题目

    AtCoder

    题目大意:

    ( 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;
    }
    
  • 相关阅读:
    Android Fragment与Activity通讯详解
    Fragment之间的交互
    理解Fragment的生命周期
    Android 利用ViewPager、Fragment、PagerTabStrip实现多页面滑动效果
    【APP UI 设计模式】(一)APP UI 设计原则和流程
    白话经典算法系列之六 高速排序 高速搞定
    究竟什么是推荐?
    Mongo散记--聚合(aggregation)&amp; 查询(Query)
    C/C++程序猿必须熟练应用的开源项目
    PL/SQL连接oracle数据库
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14880330.html
Copyright © 2011-2022 走看看