HDU-5536-Chip Factory【2015长春赛区】【字典树】

HDU-5536-Chip Factory【字典树】

        Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)

Problem Description
John is a manager of a CPU chip factory, the factory produces lots of chips everyday. To manage large amounts of products, every processor has a serial number. More specifically, the factory produces n chips today, the i-th chip produced this day has a serial number si.

At the end of the day, he packages all the chips produced this day, and send it to wholesalers. More specially, he writes a checksum number on the package, this checksum is defined as below:
maxi,j,k(si+sj)⊕sk

which i,j,k are three different integers between 1 and n. And ⊕ is symbol of bitwise XOR.

Can you help John calculate the checksum number of today?

Input
The first line of input contains an integer T indicating the total number of test cases.

The first line of each test case is an integer n, indicating the number of chips produced today. The next line has n integers s1,s2,..,sn, separated with single space, indicating serial number of each chip.

1≤T≤1000
3≤n≤1000
0≤si≤109
There are at most 10 testcases with n>100

Output
For each test case, please output an integer indicating the checksum number in a line.

Sample Input
2
3
1 2 3
3
100 200 300

Sample Output
6
400

题目链接:HDU-5536

题目大意:n个数字的序列中,找出三个数字使得(a[i] + a[j])^a[k]最大。

题目思路:现场赛的时候,一直超时没过。听学长说可以用n^3的方法暴力优化过,不过正确的解法是用01字典树。

把这n个数字保存下来建在一个01字典树上面。因为i,j,k三个数字不能重复,所以删去要用的i和j,再在里面找出能和num( a[i]+a[j])异或出的最大值。

如果num这一位上是1,就去树上找对应位的0,如果存在就由该点0往下继续找.如果不存在0就找1.(保证找出来的k值和num异或最大)

以下是代码:

#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
#define MAXN 4000005 
struct Trie  // 定义01Trie 
{
    int next[2];
    int flag,number;
    void ini()  //初始化 
    {  
        next[0] = next[1] = 0;  
        flag = 0;  
    } 
}pnode[MAXN];
int root = 0;
int tot = 0;
void Insert(int num)
{
    int rt = root;
    for (int i = 30; i >= 0; i--)
    {
        int ret;
        if (num & (1 << i)) ret = 1; //得到第i位是1还是0 
        else ret = 0;
        if (!pnode[rt].next[ret]) //如果没有这个节点 
        {
            pnode[rt].next[ret] = ++tot;    //新增加这个节点,并且把这个子节点标记为tot 
            pnode[tot].number = ret;    //tot这个子节点的值为ret 
        }  
        rt = pnode[rt].next[ret];   // 获得子节点的编号 
        pnode[rt].flag++;          //该节点所经过的flag++; 
    }
} 

void Delet (int num)    //删去该节点 
{
    int rt = root;
    for (int i = 30; i >= 0; i--)
    {   
        int ret;
        if (num & (1 << i)) ret = 1;
        else ret = 0;
        rt = pnode[rt].next[ret];
        pnode[rt].flag--;   //该节点所经过的这条路上flag--; 
    }
}

int Query(int num)
{
    int rt = root;
    for (int i = 30; i >= 0; i--)
    {
        int ret;
        if (num & (1 << i)) ret = 1;
        else ret = 0;
        if (ret == 1)   //如果为1,子节点先搜0,0不存在再走1. 
        {
            int next_node = pnode[rt].next[0];
            if (pnode[next_node].flag > 0 && next_node) rt = pnode[rt].next[0];  //0存在
            else
            {
                rt = pnode[rt].next[1];
                num ^= (1 << i);
            }   
        }
        else  //如果为0,子节点先搜1,1不存在再走0. 
        {
            int next_node = pnode[rt].next[1];
            if (pnode[next_node].flag > 0 && next_node)  //1存在 
            {
                rt = pnode[rt].next[1];
                num ^= (1 << i);
            } 
            else rt = pnode[rt].next[0];
        }   
    }
    return num;
} 
int a[MAXN];
int main(){
    int t;
    scanf("%d",&t);
    while(t--)
    {
        for(int i = 0;i < tot;i++)   //初始化 
        {  
            pnode[i].ini();  
        }

        int n,ans = 0;
        scanf("%d",&n);
        for (int i = 0; i < n; i++)
        {
            scanf("%d",&a[i]);
            Insert(a[i]);
        }
        for (int i = 0; i < n; i++)
        {
            Delet(a[i]);   //不存在相同的i,j,k所以先把i和j从字典树中删除 
            for (int j = i + 1; j < n; j++)
            {   
                Delet(a[j]);
                ans = max(Query(a[i] + a[j]),ans);
                Insert(a[j]);
            }
            Insert(a[i]);
        }
        printf("%d\n",ans); 
    } 
    return 0;
}

你可能感兴趣的:(字典树,HDU-5536)