HDU 4825 Xor Sum(01字典树解决异或问题)

本文详细解析了HDU4825 XorSum问题的解题思路,通过使用01字典树来解决异或最大值问题。介绍了如何将集合中的正整数以二进制形式存储于字典树中,并在询问时搜索最大异或值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

- HDU 4825 -

Xor Sum

Time Limit: 2000/1000 MS (Java/Others) | Memory Limit: 132768/132768 K (Java/Others)

题意:

第一行給定一个整数 T ,表示有 T 组测试数据;
每组数据第一行給定两个整数 n、m,表示集合中的元素个数和询问次数;
接下来一行有 n 个整数,这 n 个整数构成一个集合a;
之后 m 行,每行一个整数 q 代表询问的正整数。
对于每次询问,找出集合中和 q 异或结果最大的一个数。

数据范围:

T<10,1<=N,M<=100000,所有正整数均不超过2^32

解题思路:

01字典树

01字典树经常用于解决异或问题,这道题就是一个经典例子,刚开始做这道题的时候一脸蒙圈,不晓得怎么是用字典树来做,后来终于理清了思路,其实不难,就是把集合中的正整数以二进制的形式存到字典树中去,然后每次询问时,把询问的正整数也表示成二进制形式,再从最高位开始搜索字典树,寻找集合中和q异或结果最大的那个数。

但有一点要注意,那就是数组的大小,最糟糕的情况是,有100000个数(即n=100000),且每个数都有独立的32个节点(32位的二进制数),那么占用内存大小就是100000*32=3.2e6,当然这是不可能的,因为整数的二进制形式只有0和1,所以肯定有些数要和其它数共用某些节点,亲测,2e6+5是能过的,但1e6+5就太小了,不过这题给的内存空间比较大,所以即使就开3.2e6大的数组也哦可。
2e6+5: Exe.Time : 358MS | Exe.Memory : 23480K
3.2e6: Exe.Time : 405MS | Exe.Memory : 32872K

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
using namespace std;
#define INF 0x3f3f3f
#define zero 1e-7

typedef long long ll;
const int N=3.2e6+5;

int trie[N][2], quary[N];
int k;

void init() {
    k=0;
    memset(trie, 0, sizeof(trie));
    return ;
}

void inSert(int u[], int v) {
    int p=0;
    for(int i=0; i<32; i++) {
        int c=u[i];
        if(!trie[p][c])
            trie[p][c]=++k;
        p=trie[p][c];
        quary[p]=v;
    }
    return ;
}

int Search(int num[], int q) {
    int p=0;
    for(int i=0; i<32; i++) {
        int c=num[i];
        if(trie[p][c^1]) {
            p=trie[p][c^1];
        }
        else p=trie[p][c];
    }
    return quary[p];
}

int main() {
    int T, n, m, a, q;
    scanf("%d", &T);
    for(int t=1; t<=T; t++) {
        init();
        scanf("%d %d", &n, &m);
        for(int i=0; i<n; i++) {
            scanf("%d", &a);
            int b[32]={0}, d=a;
            for(int j=31; j>=0; j--) {
                b[j]=d&1;//b是a的二进制形式
                d>>=1;
            }
            inSert(b, a);
        }
        printf("Case #%d:\n", t);
        for(int i=0; i<m; i++) {
            scanf("%d", &q);
            int b[32]={0}, d=q;
            for(int j=31; j>=0; j--) {
                b[j]=d&1;//b是q的二进制形式
                d>>=1;
            }
            printf("%d\n", Search(b, q));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值