异或+字典树

题意:求n个非负数中任意2个的异或值的最大值。n数量级为10^5

分析:一个非负整数可以看成1个32位的01字符串,n个数可以看成n个字符串,因此可以建立字典树,建好树后,对于任意非负整数x,可以沿着树根往下贪心找到y,使得x异或y最大,复杂度为树的深度。

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <math.h>
 5 using namespace std;
 6 #define M 3200010
 7 #define N 100010
 8 int n;
 9 int v[N];
10 int node;
11 int next[M][2];
12 int end[M];
13 void add(int cur,int k){
14     memset(next[node],0,sizeof(next[node]));
15     end[node]=0;
16     //printf("next[%d][%d]=%d\n",cur,k,node);
17     next[cur][k]=node++;
18 }
19 int cal(int x){
20     int i,k,cur=0;
21     for(i=30;i>=0;i--){
22         k=((1<<i)&x)?0:1;
23         if(next[cur][k]) cur=next[cur][k];
24         else cur=next[cur][1-k];
25     }
26     return (x^end[cur]);
27 }
28 int main(){
29     int i,j,k,x,cur;
30     int ans;
31     while(~scanf("%d",&n)){
32         node=1;
33         memset(next[0],0,sizeof(next[0]));
34         for(i=0;i<n;i++){
35             scanf("%d",&x);
36             v[i]=x;
37             cur=0;
38             for(j=30;j>=0;j--){
39                 k=((1<<j)&x)?1:0;
40                 if(next[cur][k]==0) add(cur,k);
41                 cur=next[cur][k];
42             }
43             end[cur]=x;
44         }
45         for(ans=i=0;i<n;i++)
46             ans=max(ans,cal(v[i]));
47         printf("%d\n",ans);
48     }
49     return 0;
50 }

题目连接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1717

题意:给一个长度为n的整数序列,现在要你截取这个序列的一个前缀和一个后缀(前缀和后缀不能相交),使得前缀和后缀的异或值最大。

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <math.h>
 5 using namespace std;
 6 #define M 4200010
 7 #define N 100010
 8 int n;
 9 long long v[N];
10 long long pre[N];
11 long long suf[N];
12 int node;
13 int next[M][2];
14 void add(int i){
15     long long k,cur,x;
16     x=pre[i];
17     cur=0;
18     for(int j=42;j>=0;j--){
19         k=((1LL<<j)&x)?1:0;
20         if(next[cur][k]==0) {
21             memset(next[node],0,sizeof(next[node]));
22             next[cur][k]=node++;
23         }
24         cur=next[cur][k];
25     }
26 }
27 long long cal(long long x){
28     long long i,k,cur=0,r=0;
29     for(i=42;i>=0;i--){
30         k=((1LL<<i)&x)?0:1;
31         if(next[cur][k]) {
32             cur=next[cur][k];
33             r|=1LL<<i;
34         }
35         else cur=next[cur][1-k];
36     }
37     return r;
38 }
39 int main(){
40     int i,j;
41     long long ans;
42     while(cin>>n){
43         ans=0;
44         node=1;
45         memset(next[0],0,sizeof(next[0]));
46         for(i=1;i<=n;i++) cin>>v[i];
47         pre[0]=pre[n+1]=suf[0]=suf[n+1]=0;
48         for(i=1;i<=n;++i) pre[i]=pre[i-1]^v[i];
49         for(i=n;i>0;--i) suf[i]=suf[i+1]^v[i];
50         add(0);
51         for(i=1;i<=n+1;i++){
52             ans=max(ans,cal(suf[i]));
53             add(i);
54         }
55         cout<<ans<<endl;
56     }
57     return 0;
58 }

注意:有两个地方WA了,一个是题意说前缀后缀可以是空,另外一个是1LL而不是1,范围!!!!

posted @ 2013-04-02 21:25  _sunshine  阅读(472)  评论(0编辑  收藏  举报