Description
Xiao Ming likes to play mathematical games very much. One day, he gets a sequence of n positive integers. XOR (l , r) is defined as the XOR and of all numbers in a continuous interval. Now, Xiao Ming wants to know the intervals which make the XOR (l , r) become largest.
Require l, r.
Input
There is an integer T at the first line, indicate the case of data.
In each case, there is an integer N at the first line, indicate the length of the sequence. And there are N integers, a1, a2, … , an, at the second line. (N <= 1,000,000)
Output
In each case, the first line is “Case #k:”, k is the number of test cases, the next line includes two integers l and r, which separated by a space.
l, r output in lexicographic order if there are multiple results.
Sample Input
1 5 1 2 3 4 5
Sample Output
Case #1: 3 4
求异或和最大的区间,如果有多个区间符合要求要求,输出字典序最小的一种。
异或的性质:
1. 交换律
2. 结合律,即(a^b)^c = a^(b^c))
3. 自反性,即x^x=0
4. x^0=x
其中运用最多的就是自反性。
有上述性质,对于区间异或和要知道如下性质:
XOR[l,r] = XOR[1,l-1] ^ XOR[1,r]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
int n,num,ans,l,r,cnt;
int ch[1000003*32][2];//字典树第i层第j个子节点的编号
int idx[1000003*32];//记录字典序
void init()
{
num=0;cnt=1;ans=l=r=0;
memset(idx,INF,sizeof(idx));
memset(ch[0],0,sizeof(ch[0]));
}
void Insert(int id,int x)//要插入数的编号,要插入数
{
int k=0;
for(int i=31;i>=0;i--)
{
int tmp=(x>>i)&1;
if(!ch[k][tmp])
{
memset(ch[cnt],0,sizeof(ch[cnt]));
ch[k][tmp]=cnt++;
}
k=ch[k][tmp];
}
if(id<idx[k])
idx[k]=id;//保证同一个异或和的字典序最小。每一个k值代表一个异或和
}
void query(int id,int x)
{
int k=0,res=0;
for(int i=31;i>=0;i--)
{
int tmp=(x>>i)&1;//贪心策略,从高位开始,让高位尽可能的为1,那么这个数位如果是1,那么就找0(1^1),如果是0,那么就找1(0^1);
if(ch[k][tmp^1])
{
k=ch[k][tmp^1];
res+=(1<<i);
}
else
{
k=ch[k][tmp];
res+=(0<<i);
}//如果并没有,那么往下贪心,这一位不变
}
if(res>ans)
{
ans=res;
l=idx[k];
r=id;
}
else if(res==ans)
{
if(idx[k]<l)
{
l=idx[k];
r=id;
}
else if(idx[k]==l&&id<r)
{
r=id;
}
}
}
int main()
{
int T,x;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
scanf("%d",&n);
printf("Case #%d:\n",cas);
init();
Insert(0,0);
for(int i=1;i<=n;i++)//枚举r
{
scanf("%d",&x);
num^=x;
Insert(i,num);
query(i,num);
}
printf("%d %d\n",l+1,r);//因为XOR[l,r] = XOR[1,l-1] ^ XOR[1,r],所以l需要+1
}
return 0;
}