HDU 4825 Xor Sum(经典01字典树+贪心)

Xor Sum

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 1555    Accepted Submission(s): 657

Problem Description

Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大。Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助。你能证明人类的智慧么?

Input

输入包含若干组测试数据,每组测试数据包含若干行。
输入的第一行是一个整数T(T < 10),表示共有T组数据。
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。

Output

对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
对于每个询问,输出一个正整数K,使得K与S异或值最大。

Sample Input

2

3 2

3 4 5

1

5

4 1

4 6 5 6

3

Sample Output

Case #1:

4

3

Case #2:

4

题目链接:HDU 4825

学习这个也学了挺久的,苦于能百度到的详细资料甚少,尤其很多是用静态数组开写的(节省内存看起来有一点麻烦),好像这题没看见用动态链表来写的(目前还是入门阶段就一直用着new或malloc写),今天看了好一会儿的代码终于看出一点头绪了

题目本身非常经典,就是给一堆数(就记为 X吧)又给Q个询问,每次又给出一个特定的数S,求(Xi^S)的最大值。

首先异或就是两个二进制位置上的数不同就可以得到1相同则得到0,比如(10100)2^(01111)2=(11011)2,可以转换成十进制验证:20^15=27。

然后把每一个数都转换成二进制(位置要对齐,前面不足则补0),转换的长度就跟题目给的数据范围有关了,此题就33位就够了。更新字典树的顺序和过程与普通单词字典树一模一样,从左到右地遍历插入各位二进制数值,但显然next指针只有两个——next[0]与next[1],更新的最后把原来的值附到结尾节点的val上,表示这整条路对应的十进制是val。

然后如何求最大异或值呢,先要知道一般情况下正项等比数列前n-1项求和的值肯定要小于第n项的值,那也就是说最坏情况下走第x个节点而x+1~n均只能得到0的时候,也比不走x而x+1~n均得到1的情况好。

然后假设已经得到了最大异或值Max,那Max异或K就可以得到某个数Xi了,此时不知道Xi是什么,但是可以通过贪心找到它。

贪心从最高位也就是树的开始位置直接往当前二进制位值取反的节点走,走到底那个节点的val就是我们要找的Xi,这里我直接用bitset来代替位运算直观一点

代码:

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=33;
struct info
{
    info *nxt[2];
    int val;
    info()
    {
        val=0;
        fill(nxt,nxt+2,nullptr);
    }
};
info *L;
void update(int n)
{
    bitset<N> bit=n;
    int i,indx;
    info *cur=L;
    for (i=32; i>=0; --i)
    {
        indx=bit[i];
        if(!cur->nxt[indx])
        {
            info *one=new info();
            cur->nxt[indx]=one;
            cur=one;
        }
        else
            cur=cur->nxt[indx];
    }
    cur->val=n;//末位置节点附着
}
int query(int k)
{
    bitset<N> bit=k;
    info *cur=L;
    int indx,i;
    for (i=32; i>=0; --i)
    {
        indx=bit[i];
        if(cur->nxt[indx^1])//往取反位置走
            cur=cur->nxt[indx^1];
        else
            cur=cur->nxt[indx];//没有的话只能继续往前走
    }
    return cur->val;
}
void desinfo(info *cur)//删除字典树释放内存防止MLE
{
    for (int i=0; i<2; ++i)
        if(cur->nxt[i])
            desinfo(cur->nxt[i]);
    delete cur;
}
int main(void)
{
    int T,n,m,i,s,val;
    scanf("%d",&T);
    for (int q=1; q<=T; ++q)
    {
        L=new info();
        scanf("%d%d",&n,&m);
        for (i=0; i<n; ++i)
        {
            scanf("%d",&val);
            update(val);
        }
        printf("Case #%d:\n",q);
        for (i=0; i<m; ++i)
        {
            scanf("%d",&s);
            printf("%d\n",query(s));
        }
        //desinfo(L);
    }
    return 0;
}
时间: 2024-10-12 13:04:22

HDU 4825 Xor Sum(经典01字典树+贪心)的相关文章

HDU 4825 Xor Sum(01字典树入门题)

http://acm.hdu.edu.cn/showproblem.php?pid=4825 题意: 给出一些数,然后给出多个询问,每个询问要从之前给出的数中选择异或起来后值最大的数. 思路:将给出的数建立01字典树,从高位开始建树.对于每个询问,如果当前位置值为0,那么在字典树中,如果有1的值,那么就优先走1,否则再走0. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using names

HDU - 4825 Xor Sum(01字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4825 题目: Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大.Prometheus 为了让 Zeus 看到人类的伟

HDU 4825 Xor Sum 【01字典树】

题面: Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大.Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助.你能证明人类的智慧么? Input 输入包含若干组测试数据,每组

HDU 4825 Xor Sum(01字典树)题解

思路:先把所有数字存进字典树,然后从最高位贪心. 代码: #include<set> #include<map> #include<stack> #include<cmath> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm>

2014百度之星资格赛—— Xor Sum(01字典树)

Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 0    Accepted Submission(s): 0 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起

【Hdu4825】Xor Sum(01字典树)

Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大.Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助.你能证明人类的智慧么? Solution 01字典树入门题 Code #include

HDU 4825 Xor Sum 字典树+位运算

点击打开链接 Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 291    Accepted Submission(s): 151 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus

HDU 4825 Xor Sum(二进制的字典树,数组模拟)

题目 //居然可以用字典树...//用cin,cout等输入输出会超时 //这是从别处复制来的 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int node[3011111][2]; int tag,m,n,cas=0,T; long long one[64],allone,tmp; //0/1树的加数据操作,增加一个32的数 //其中如果当前位是0,则加左儿子,

hdu 4825 Xor Sum(trie+贪心)

hdu 4825 Xor Sum(trie+贪心) 刚刚补了前天的CF的D题再做这题感觉轻松了许多.简直一个模子啊...跑树上异或x最大值.贪心地让某位的值与x对应位的值不同即可. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #define CLR(a,b) memset((a)