Cow XOR奶牛异或
Time Limit:10000MS Memory Limit:65536K
Total Submit:138 Accepted:56
Case Time Limit:500MS
Description
农民约翰在喂奶牛的时候被另一个问题卡住了。他的所有N(1 <= N <= 100,000)个奶牛在他面前排成一行(按序号1..N的顺序),按照它们的社会等级排序。奶牛#1有最高的社会等级,奶牛#N最低。每个奶牛同时被指定了一个不唯一的附加值,这个数在0..2^21 - 1的范围内。
帮助农民约翰找出应该从哪一头奶牛开始喂,使得从这头奶牛开始的一个连续的子序列上,奶牛的附加值的异或最大。
如果有多个这样的子序列,选择结尾的奶牛社会等级最高的。如果还不唯一,选择最短的。
Input
第1行:一个单独的整数N。
第2到N + 1行:N个0..2^21 - 1之间的整数,代表每头奶牛的被赋予的数。第j行描述了社会等级j - 1的奶牛。
Output
第 1 行: 3个空格隔开的整数,分别为:最大的异或值,序列的起始位置、终止位置。 时限0.5秒
Sample Input
5
1
0
5
4
2
Sample Output
6 4 5
Hint
最大异或值为6,从第4个开始喂,到第5个结束。
4 异或 2 = 6
(100) 异或 (010) = (110)
Source
【USACO6.1.3】
由于异或运算与加法运算类似,都可以用前缀存储,想到用前缀异或优化,即f[i]=a[1]^a[2]^……^a[i].
分析:
j从1到n依次枚举每个数字,a[j]与哪一个a[i]异或的值最大呢?(1<=i<=j-1)
把a[1]到a[j-1]按二进制位插入到trie中,最高位与根相连,最低位为叶子节点。
原本应该让a[j]与a[1]到a[j-1]依次取异或,时间复杂度太高,不可取。
考虑用贪心的方法,让异或后的高位尽可能为1,所以在查询trie时,
尽量选让高位异或结果为1的路线,实在不行才选为0的路线往叶子节点走。
每次查询的时间复杂度为O(20)
#include<cstdio> #include<iostream> const int m=20; int n; int f[200005]; struct node{int kid[2],num;}trie[2000005]; int tot=1; void insert(int k){//插入函数 int t=1,i; for(i=m;i>=0;i--){//从最高位开始讨论存储 int now=(f[k]>>i)&1;//取出高位 if(trie[t].kid[now]==0) trie[t].kid[now]=++tot; t=trie[t].kid[now]; } trie[t].num=k; } int find(int k){//查询函数(查找与当前数异或值最大的数) int t=1,i; for(i=m;i>=0;i--){ int now=1-(f[k]>>i)&1;//尽量找与当前数相反的数使异或值最大 if(trie[t].kid[now]!=0)t=trie[t].kid[now]; else t=trie[t].kid[1-now]; } return trie[t].num; } int main(){ scanf("%d",&n); int i,x; int s=1,t=1; for(i=1;i<=n;i++){ scanf("%d",&x); f[i]=f[i-1]^x; } int ans=f[1]; insert(1); for(i=2;i<=n;i++){ int p=find(i); if((f[i]^f[p])>ans){ ans=f[i]^f[p]; s=p+1; t=i; } insert(i); } printf("%d %d %d",ans,s,t); }