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。
输入的第一行是一个整数T(T < 10),表示共有T组数据。
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。
Output
对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
对于每个询问,输出一个正整数K,使得K与S异或值最大。
对于每个询问,输出一个正整数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:\n",++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\n",nums); } deletetire(root); } }