快晴

导航

acwing 143. 最大异或对

今回是Jill镇楼,

 

今天题目还是感觉很有意思的,我推荐大家都做,做对了就做爽了(

题干:

在给定的 NN 个整数 A1A2ANA1,A2……AN 中选出两个进行 xorxor(异或)运算,得到的结果最大是多少?

输入格式

第一行输入一个整数 NN。

第二行输入 NN 个整数 A1A1~ANAN。

输出格式

输出一个整数表示答案。

数据范围

1N1051≤N≤105,
0Ai<2310≤Ai<231

输入样例:

3
1 2 3

输出样例:

3

暴力我们就不解释了,一个个对比是O(n^2),复杂度爆了。

我们看题目要求异或值,自然会想到二进制。

假设我们有一个图,图上有所有给出数的二进制表示,

我们如何给出关于一个数的最大异或值?

我们只要找每一个对应二进制位数尽量相反(位数从高到低选取),就能保证有最大异或值。

如果我们找n个数的任意两个数最大的异或值,最坏只有O(n*32);

自然会想到只有零一的左右儿子的二叉树,我们一建树,一看题目,空间爆了(

我们然后就会想到用字典数的建树方法来建这个只有零一的二叉树。

结果,代码如下啦:

#include<cstdio>
#include<cmath>
#include<cstring>
const int maxn = 1e5 + 10;
int bit[33 * maxn][2], n, k, a[maxn], t[35];
inline int max(int a, int b)
{return a > b ? a : b;}
void into(int x)
{
    int p = 1,pos=0,i=0,tp=x;
    memset(t, 0, sizeof t);
    while (x)
    {
        t[p] = x % 2;
        x = x / 2;
        ++p;
    }
    for (i = 32; i; --i)
    {
        if(!bit[pos][t[i]])
        bit[pos][t[i]] = ++k;
        pos = bit[pos][t[i]];
    }
}
int find(int x)
{
    int pos = 0, maxx = 0, ans[35] = { 0 }, p = 1, v = 0;
    memset(t, 0, sizeof t);
    while (x)
    {
        t[p] = x % 2;
        x = x / 2;
        ++p;
    }
    for (int i = 32; i; --i)
    {
        if (bit[pos][!t[i]])ans[i] = 1, v = !t[i];
        else ans[i] = 0, v = t[i];
        pos = bit[pos][v];
    }
    for (int i = 32; i; --i)
        maxx += ans[i] * pow(2, i - 1);
    return maxx;
}
int main()
{
    int ans = 0;
    freopen("C:\\Users\\Towetrlone\\Desktop\\qwq.txt", "r", stdin);
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]),into(a[i]);
    for (int i = 1; i <= n; ++i)
        ans = max(ans, find(a[i]));
    printf("%d", ans);
    return 0;
}

 

posted on 2021-06-28 22:06  快晴  阅读(49)  评论(0编辑  收藏  举报