Xor sum(字典树+贪心)

题目:传送门

前提小知识:

因为很菜,所以我不知道

a^b=c可逆
如果已知a^b=cc^b=a c^a=b

题意:

给n个数m次询问 每次询问一个s 问:n个数中,哪个数异或s最大

一般解法:

普通解法:遍历m遍,每次循环n,然后利用比较得最大
时间复杂度: O(n*m)

前缀树解法:

建树:插入操作是O(n)的复杂度,查询操作是O(32)的复杂度,故查询是O(1),时间复杂度为O(n+m),故为O(n)

很显然这道题O(n*m)的时间复杂度过不去,需要用O(n)的时间复杂度,所以神奇的01字典树出现了

题解:

首先:我们如何利用前缀性,去造一颗字典树,对于数字,我们可以想到,把数字改成一串二进制数不就ok了,对于一串数字,我们可以利用其前缀性,造一颗字典树。造出字典树后,我们需要写一个贪心去查找,这里就用到a^b=c可逆
贪心思路:
如果我们让异或尽可能大,则最优情况是每一位都为1,由于最大位数是32位,所以我们最优情况是321,那么我们可以由a^b=1,由于其可逆性,得出字典树上是否存在a,a=b^1,如果存在就转为这个节点,如果不存在,就用当前节点即可,直到查询到最后的节点,返回值即可

注意:要开long long 因为 int形不存在>>32
如果用int >>31 左移31即可

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
int tree[32*maxn][2];//儿子只有两种类型的
int max_num[32*maxn];
int tot;
void insert_num(int k)
{
    int root=0;
    for(int i=31; i>=0; i--)
    {
        int id=(k>>i)&1;
        if(!tree[root][id])
            tree[root][id]=++tot;
        root=tree[root][id];
    }
    max_num[root]=k;
}
int find_num(int s)
{
    int root=0;
    for(int i=31; i>=0; i--)
    {
        int id=(s>>i)&1;
        if(tree[root][id^1])
            root=tree[root][id^1];
        else
        {
            root=tree[root][id];
        }
    }
    return max_num[root];
}
int main()
{
    int n,m,t,d=0;

    scanf("%d",&t);
    while(t--)
    {

        memset(tree,0,sizeof(tree));
        //memset(max_num,0,sizeof(max_num));
        scanf("%d %d",&n,&m);
        //tot=0;

        for(int i=1; i<=n; i++)
        {
            int x;
            scanf("%d",&x);
            insert_num(x);
        }
//        printf("%d\n",find_num(5));
        printf("Case #%d:\n",++d);
        while(m--)
        {
            int y;
            scanf("%d",&y);
            printf("%d\n",find_num(y));
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值