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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM