Xor Sum
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 4445 Accepted Submission(s): 652
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
题解
本题数据量非常大。感觉直接暴力时间复杂度O(n*m)会超时,只是想到去年网赛有道题数据量也非常大直接暴力居然过了于是直接敲了敲,终于还是TLE了。
想到位操作运算符的通用思想,逐位处理,相应本题还是比較easy想到字典树的,Memory Limit: 132768/132768 K (Java/Others)。提示能够尝试牺牲空间换取时间,直接字典树空间消耗为2^32。但本题数据相对此规模还是比較小的,一共n个数,总共32*n位,所以空间复杂度为O(n)。能够接受。
先用原序列中的数按位建立字典树。然后将查找过程中用待询问数与0xffffffff异或XOR来在字典树上跑。终于找到的即为最大的。如果按查询的XOR的某个分支不存在,则想还有一分支进行,这样答案可能变小,可是正确的,总的时间复杂度O(m*log(32)),常数能够不计。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN=100000*32+100;
__int64 tree[MAXN][2];
__int64 node[MAXN];
__int64 tot;
void insert(__int64 a)
{
__int64 j;
int bit,dep=0;
for(j=31;j>=0;j--)
{
bit=((0x1<<j)&a)?0x1:0x0;
if(tree[dep][bit]==0)
{
tree[dep][bit]=tot++;
memset(tree[tree[dep][bit]], 0, sizeof(tree[tree[dep][bit]]));
}
dep=tree[dep][bit];
}
node[dep]=a;
}
__int64 Solve(__int64 val)
{
__int64 j,bit;
int dep=0;
for(j=31;j>=0;j--)
{
bit=((0x1<<j)&val)?0x0:0x1;
if(tree[dep][bit])dep=tree[dep][bit];
else dep=tree[dep][bit^1];
}
return node[dep];
}
int main()
{
int cas;
__int64 n,m,j,s,a;
int tag=0;
cin>>cas;
while(cas--)
{
tot=1;
scanf("%I64d%I64d",&n,&m);
memset(tree[0],0,sizeof(tree[0]));
while(n--)
{
scanf("%I64d",&a);
insert(a);
}
printf("Case #%d:
",++tag);
while(m--)
{
scanf("%I64d",&s);
printf("%I64d
",Solve(s));
}
}
return 0;
}