• Codeforces 1285D Dr. Evil Underscores


    Description

    描述

    给一个长度为 $n$ 的数组 $a$,试找到一个 $X$,使得 $maxlimits_{1le i le n} (a_i oplus X)$ 最小,输出这个最小值即可。

    输入

    第一行一个数 $n(1 le n le 10^5)$,接下来第二行 $n$ 个数表示 $a$ 数组 $(0le a_i le 2^{30} - 1)$。

    输出

    一行一个数,表示所求最小值。

    样例

    输入1

    3
    1 2 3

    输出1

    2

    输入2

    2
    1 5

    输出2

    4

    解释

    在第一个样例中,我们可以选 $X = 3$。

    在第一个样例中,我们可以选 $X = 5$。

    Solution

    看到异或,很自然想到从高位到低位贪心。如果较高的位置是能设为 $0$ 的,那一定将它设为 $0$,这样的答案一定最优。

    我们可以对数集建 01-trie,为了适应从高位到低位的贪心,我们将第一层(也就是根节点所在的那一层)的 $dep$ 设为 $30$,从上到下依次 $-1$,得到一个总深度为 $30$ 的 trie,$dep = i$ 的层表示的是 $i$ 位的数字,位数从 $0$ 开始计算,最高到 $29$ 位,可以满足题目中 $a_i < 2^{30}$ 的要求。

    比如样例,有三个数 $1, 2, 3$,我们的 01-trie 是这个样子的:

    $ullet$ 插入 $1$:

    $ullet$ 插入 $2$:

    $ullet$ 插入 $3$:

     插入的代码不难写出:

    void insert(LL rt, LL val, LL dep)
    {
    	o[rt].dep = dep;
    	if(!dep) return;
    	if(!o[rt].ch[val >> dep - 1 & 1]) o[rt].ch[val >> dep - 1 & 1] = ++siz;
    	insert(o[rt].ch[val >> dep - 1 & 1], val, dep - 1);
    }
    

    然后就可以在 01-trie 上 DP,在每个结点维护一个 $res$,表示以它为根的树的答案。比如现在要求 $res_{rt}$ 根据树形 DP 的基本操作,当然是先递归它的儿子,然后分类讨论一下:

      $ullet$ 如果 $rt$ 只有一个儿子,那么如果是 $ch_0$,$X$ 的这位就设成 $0$(保持不变),否则就设为 $1$(取反),总有办法使得这个位置的答案是 $0$,所以直接返回该儿子的 $res$ 即可

      $ullet$ 如果 $rt$ 两个儿子都有,那么如果 $X$ 这位设成 $0$,$ch_1$ 的该位就依然是 $1$;如果设为 $1$,$ch_0$ 的该位就变成了 $1$,既然 $2^{dep_{rt} - 1}$($-1$ 因为是儿子那位的答案,写成 $2 ^{dep_{son}}$ 也行)逃不掉了,在此基础上加上 $min(res_{ch_0}, res_{ch_1})$ 再返回即可

    DP 的代码:

    void solve(LL rt)
    {
    	if(o[rt].ch[0]) solve(o[rt].ch[0]);
    	if(o[rt].ch[1]) solve(o[rt].ch[1]);
    	if(o[rt].ch[0] && o[rt].ch[1])
    		o[rt].res = min(o[o[rt].ch[0]].res, o[o[rt].ch[1]].res) + (1LL << o[rt].dep - 1);
    	else o[rt].res = o[o[rt].ch[0]].res + o[o[rt].ch[1]].res;
    }

    最后根节点 $1$ 的 $res$ 就是答案,完整的代码给出,供参考。

    #include <bits/stdc++.h>
    #define ROOT 1
    using namespace std;
    typedef long long LL;
    const int N = 2e5 + 5;
    struct node
    {
    	LL res, dep, ch[2];
    	node() { res = dep = ch[0] = ch[1] = 0; } 
    } o[N * 20];
    LL a[N], n, siz = 1;
    void insert(LL rt, LL val, LL dep)
    {
    	o[rt].dep = dep;
    	if(!dep) return;
    	if(!o[rt].ch[val >> dep - 1 & 1]) o[rt].ch[val >> dep - 1 & 1] = ++siz;
    	insert(o[rt].ch[val >> dep - 1 & 1], val, dep - 1);
    }
    void solve(LL rt)
    {
    	if(o[rt].ch[0]) solve(o[rt].ch[0]);
    	if(o[rt].ch[1]) solve(o[rt].ch[1]);
    	if(o[rt].ch[0] && o[rt].ch[1])
    		o[rt].res = min(o[o[rt].ch[0]].res, o[o[rt].ch[1]].res) + (1LL << o[rt].dep - 1);
    	else o[rt].res = o[o[rt].ch[0]].res + o[o[rt].ch[1]].res;
    }
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin >> n;
    	for(int i = 1; i <= n; i++)
    	{
    		cin >> a[i];
    		insert(ROOT, a[i], 30);
    	}
    	solve(ROOT);
    	cout << o[ROOT].res << endl;
    	return 0;
    }
  • 相关阅读:
    非科班毕业生四个月的面试准备,网易三轮面面试,成功拿下offer(面经奉上)全靠这份阿里面试手册
    太赞了!华为鸿蒙工程师总结的Linux笔记,提供下载
    阿里java岗面试有多难?分享阿里面试真题(附面试专题答案)及P7所要掌握的技能体系!
    阿里腾讯百度等大厂2020秋招面试总结,内附答案
    小小码农的大梦想,2020最新BAT大厂面试题干货总结
    历经三个月的紧张复习,秋招终于进了百度,附上面经分享希望可以帮助大家
    这份《高性能MySQL》适合数据库管理员(DBA)阅读,也适合开发人员参考学习
    这份程序员必备书籍《Spring实战4》,你确定不看看?
    自学JAVA的我提交给2020的问卷答案,JAVA核心知识点分享这一年来的努力并没有白费!
    Delphi连接数据库的两种方式
  • 原文地址:https://www.cnblogs.com/syksykCCC/p/CF285D.html
Copyright © 2020-2023  润新知