FJUT ACM 2160 Xor Sum

Xor Sum

TimeLimit:1000MS  MemoryLimit:132768KB
64-bit integer IO format:%I64d
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异或值最大。
SampleInput
2
3 2
3 4 5
1
5
4 1
4 6 5 6
3
SampleOutput
Case #1:
4
3
Case #2:
4
【思路】:看见题目第一直觉就是直接异或,然后比较就可以ac,当然结果是一个TLE,因为询问次数跟次数都太大了,
O(N^2)的复杂度是必定超时的,其实这题是可以用字典树进行优化的,因为要找到异或的最大值,我们完全可以讲输入的
值建成一颗0,1字典树,而输入每个值要异或最大,就必须选择匹配度较高的二进制树,一开始我是从低位向高位搜索,结果
发现案例过不了,因为我们可以得到2^2>∑(2^0*1+2^1*1);所以说只要一个高位的是1,就算是低位全是1也比他来得小
那我们就必须从高位向低位进行查找,但是有个问题无法解决,就是很多个数的二进制数的位长不一样,所以我观察了题目的数据
最大不会超过2^33,所以我就开了一个35的数组来储存一个数的所有位数,然后不够的全部补0,就可以等长来建字典树,然后输入
取反的过程要注意为0的高位都得变成1;然后再去匹配,匹配的时候顺带计算,就可以得出结果,一开始我用这个思路又TLE了一发,
后来CWL学长发现我再计算数值时用了pow(),太慢,修改之后就ac了,emmmmmmm
真的死在pow();
贴上代码:(01字典树)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef long long ll;
typedef struct node
{
    int n;
    struct node *next[2];
} tire;
tire *creattire()
{
    tire *q;
    q=(tire *)malloc(sizeof(tire));
    q->n=0;
    for(int i=0; i<2; i++)
    {
        q->next[i]=NULL;
    }
    return q;
}
void addtire(int word[],tire *root,int n)
{
    for(int i=0; i<=n; i++)
    {
        int ans=word[i];
        if(root->next[ans]==NULL)
        {
            tire *q;
            q=creattire();
            root->next[ans]=q;
            root=root->next[ans];
        }
        else
            root=root->next[ans];
    }
}
void deletetire(tire *root)
{
    if(root==NULL)
        return ;
    for(int i=0; i<2; i++)
    {
        if(root->next[i]!=NULL)
        {
            deletetire(root->next[i]);
        }
    }
    free(root);
}
ll remath(int word[],tire *root,int n)
{
    int team[40];
    int j=0;
    for(int i=0; i<=n; i++)
    {
        if(root->next[word[i]]!=NULL)
        {
            team[j++]=word[i];
            root=root->next[word[i]];
        }
        else
        {
            if(word[i]==0)
            {
                team[j++]=1;
                root=root->next[1];
            }
            else
            {
                team[j++]=0;
                root=root->next[0];
            }
        }
    }
    ll sum=0;
    for(int i=n; i!=-1; i--)
    {
        sum+=team[i]*(1<<(n-i));///使用pow()TLE
    }
    return sum;
}
int word[40];
int main()
{
    int t;
    tire *root;
    scanf("%d",&t);
    int y=0;
    while(t--)
    {
        printf("Case #%d:
",++y);
        int n,k;
        scanf("%d%d",&n,&k);
        root=creattire();
        for(int i=0; i<n; i++)
        {
            ll num;
            int j=35;
            scanf("%I64d",&num);
            memset(word,0,sizeof(word));
            while(num!=0)
            {
                if(num&1)
                    word[j--]=1;
                else
                    word[j--]=0;
                num>>=1;
            }
            addtire(word,root,35);
        }
        for(int i=0; i<k; i++)
        {
            ll nums;
            scanf("%I64d",&nums);
            for(int i=0; i<40; i++)
                word[i]=1;
            int j=35;
            while(nums!=0)
            {
                if(nums&1)
                    word[j--]=0;
                else
                    word[j--]=1;
                nums>>=1;
            }
            nums=remath(word,root,35);
            printf("%I64d
",nums);
        }
        deletetire(root);
    }
}
原文地址:https://www.cnblogs.com/qq136155330/p/8580672.html