题意:
给你一个长度为n的序列,让你选择你个连续的子序列做Xor操作求最大值为多少?并且该区间是什么?(如果有多个解,则取右边界最小(第一关键词),区间长度最短(第二关键词))。
思路:
对数组求前缀异或和,即求[1,2][1,3]....[1,n]等区间的异或和,然后你将二个区间异或后可以发现是一个连续区间的异或和。然后用01trie求取结果。
注意当n=1时的结果。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[33], cnt[3200005][2], ji=1;
ll pa[100005];
ll ma=-1;
void Insert()
{
int now=0, i=31;
while(i>=0)
{
if(cnt[now][a[i]]==-1)
{
cnt[now][a[i]]=ji;
ji++;
}
now=cnt[now][a[i]];
i--;
}
}
ll fun()
{
ll now=0, p=0, k=(1LL<<31), i=31;
while(i>=0)
{
if(a[i]==1&&cnt[now][0]!=-1)
{
p=p+k;
now=cnt[now][0];
}
else if(a[i]==0&&cnt[now][1]!=-1)
{
p=p+k;
now=cnt[now][1];
}
else if(a[i]==1&&cnt[now][1]!=-1)
{
now=cnt[now][1];
}
else
{
now=cnt[now][0];
}
i--;
k=k/2;
}
return p;
}
int main()
{
int n, r=-1;
scanf("%d",&n);
memset(cnt,-1,sizeof(cnt));
for(int i=0; i<n; i++)
{
scanf("%lld",&pa[i]);
}
ma=pa[0];
for(int i=0; i<n; i++)
{
if(i!=0)
{
pa[i]=pa[i-1]^pa[i];
}
int x=pa[i];
for(int j=0; j<32; j++)
{
a[j]=x%2;
x=x/2;
}
Insert();
ll pan=fun();
if(pan>ma)
{
ma=pan;
r=i;
}
}
//printf("%lld %lld\n",pa[1],pa[2]);
ll l=-1;
for(int i=r-1; i>=0; i--)
{
if((pa[i]^pa[r])==ma)
{
l=i;
//printf("%lld %lld\n",pa[i],pa[r]);
//printf("l=%lld\n",r);
break;
}
}
if(pa[0]==ma)
{
cout << pa[0] << " " << 1 << " " << 1 << endl;
}
else
{
cout << ma << " " << l+2 << " " << r+1 << endl;
}
return 0;
}

京公网安备 11010502036488号