-
[1525] Cow Xor
- 时间限制: 2000 ms 内存限制: 65535 K
- 问题描述
-
农民约翰在喂奶牛的时候被另一个问题卡住了。他的所有N(1 <= N <= 100,000)个奶牛在他面前排成一行(按序号1..N的顺序),按照它们的社会等级排序。奶牛#1有最高的社会等级,奶牛#N最低。每个奶牛同时被指定了一个不唯一的附加值,这个数在0..2^21 - 1的范围内。
帮助农民约翰找出应该从哪一头奶牛开始喂,使得从这头奶牛开始的一个连续的子序列上,奶牛的附加值的异或最大。
如果有多个这样的子序列,选择结尾的奶牛社会等级最高的。如果还不唯一,选择最短的。
- 输入
-
第1行:一个单独的整数N。
第2到N + 1行:N个0..2^21 - 1之间的整数,代表每头奶牛的被赋予的数。第j行描述了社会等级j - 1的奶牛。 - 输出
-
第 1 行: 3个空格隔开的整数,分别为:最大的异或值,序列的起始位置、终止位置
- 样例输入
-
5 1 0 5 4 2
- 样例输出
-
6 4 5
- 提示
-
最大异或值为6,从第4个开始喂,到第5个结束。 4 异或 2 = 6 (100) 异或 (010) = (110)
- 来源
-
USACO (NOCOW)
题目链接:NBUT 1525
求一段连续异或最大值,假设连续区间为[L,R]则是由pre[L-1]^pre[R]而来,然后枚举每一个pre[i]即可,每一次查找的时间复杂度为O(20)左右,然后题目就变成了求两个pre的最大异或和的情况,跟xorsum就一样了,不过要注意的是对pre[i]求出来的最优异或组合pre[j]后其实得到的是最优xorsum[i+1,j],因此左区间要加一;除此之外根据题意进行特判并且还有要考虑直接取当前值区间端点相等时候特判,调试调试就差不多了。
给几组容易错的数据:
5
5 5 6 6 7
答案为 7 5 5(题目数据不够强,之前代码答案为7 4 5 也可以AC)
5
0 1 1 0 0
答案为 1 2 2
代码:
#include <stdio.h> #include <iostream> #include <algorithm> #include <cstdlib> #include <sstream> #include <cstring> #include <bitset> #include <string> #include <deque> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define CLR(x,y) memset(x,y,sizeof(x)) #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) typedef pair<int,int> pii; typedef long long LL; const double PI=acos(-1.0); const int N=100010; struct info { int val,S; info *nxt[2]; info() { val=0; S=-1; nxt[0]=nxt[1]=NULL; } }; info *L; int arr[N]; int pre[N]; void update(int n,int p) { bitset<21> bit(n); info *cur=L; int indx,i; for (i=20; i>=0; --i) { indx=bit[i]; if(cur->nxt[indx]) cur=cur->nxt[indx]; else { info *one=new info(); cur->nxt[indx]=one; cur=one; } } cur->val=n; if(cur->S==-1||p<cur->S)//前缀结尾位置尽量靠前 cur->S=p; } pii query(int n) { info *cur=L; bitset<21> bit(n); int indx,i; for (i=20; i>=0; --i) { indx=bit[i]; if(cur->nxt[indx^1]) cur=cur->nxt[indx^1]; else cur=cur->nxt[indx]; } return pii(cur->val,cur->S); } int read() { int res=0,ch,flag=0; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0'; return flag?-res:res; } int main(void) { int n,i,l,r,ans,val; while (~scanf("%d",&n)) { getchar(); arr[0]=0; L=new info(); for (i=1; i<=n; ++i) { arr[i]=read(); pre[i]=pre[i-1]^arr[i]; update(pre[i],i); } int tl,tr,dx,res; ans=0; for (i=0; i<=n; ++i) { pii temp=query(pre[i]); res=max(temp.first^pre[i],arr[i]); tl=min(temp.second+1,i); tr=max(temp.second,i); dx=tr-tl; if(arr[i]==res) { if(i<tr) { tl=tr=i; dx=0; } else if(i==tr&&0<dx) { dx=0; tl=tr=i; } } if(res>ans) { ans=res; l=tl; r=tr; } else if(res==ans) { if(r>tr) { r=tr; l=tl; } else if(r==tr&&dx<r-l) l=tl; } } printf("%d %d %d ",ans,l,r); } return 0; }