ACM学习历程—CSU 1216 异或最大值(xor && 贪心 && 字典树)

题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1216

题目大意是给了n个数,然后取出两个数,使得xor值最大。

首先暴力枚举是C(n, 2),显然不行。

考虑每一个数,显然,从最高位开始,如果它能和某一个数xor,让最高位为1,效果肯定是最佳的。其次考虑次高位,以此类推。

简单说,就是x的某一位,如果能找到某些数与x这一位xor1,则考虑这些数,然后比较下一位;否则,就直接考虑下一位。起始从最高位开始考虑。

在这种贪心策略下,用字典树保存搜索每一位的效率比较高。

需要注意的是,由于是xor运算,所以需要保证每一个数的位数一样长,因为是32位有符号的int型,于是统一成31位长。

还有就是,理论上需要先把所有数,存入字典树,然后讨论每一个数,但是对于一个x,如果它能和y这个数xor出最大值,那么不管是先存入了x,还是先存入了y(x, y)这个数对是肯定会被讨论的。所以,完全可以存入一个数,就讨论一个数。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <string>
#define LL long long

using namespace std;

const int maxN = 100005;
const int len = 31;//len表示数的二进制最大长度
struct Trie
{
    int next[2];
}tree[maxN*len];
int cnt, ans, n;

void initTree()
{
    cnt = 0;
    memset(tree, -1, sizeof(tree));
}

void add(int x)
{
    int now = 0;
    bool k;
    for (int i = len; i >= 0; i--)
    {
        k = x&(1<<i);
        if (tree[now].next[k] == -1)
            tree[now].next[k] = ++cnt;
        now = tree[now].next[k];
    }
}

//返回当前数中能和x合成最大数的数
int query(int x)
{
    int v = 0, now = 0;
    bool k;
    for (int i = len; i >= 0; i--)
    {
        k = x&(1<<i);
        if (tree[now].next[!k] != -1)
            k = !k;
        v = v|(k<<i);
        now = tree[now].next[k];
    }
    return v;
}

void work()
{
    ans = 0;
    initTree();
    int x;
    for (int i = 0; i < n; ++i)
    {
        scanf("%d", &x);
        add(x);
        ans = max(ans, x^query(x));
    }
    printf("%d\n", ans);
}

int main()
{
    //freopen("test.in", "r", stdin);
    while (scanf("%d", &n) != EOF)
    {
        work();
    }
    return 0;
}
View Code

 

posted on 2015-11-10 17:40  AndyQsmart  阅读(2307)  评论(0编辑  收藏  举报

导航