题意:中文题。
分析:枚举每个元素,将它当成那个次大值,然后在它所作用的区间内找异或最大值即可。怎么找它作用的区间呢?用set和priority_queue一起,用优先队列使得大的元素的位置先进set。然后对于每一个新位置找他前面和后面的位置边界即可。我写得好丑~O(nlog(max(a[i])))
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=50100;
const int MAX=1000000100;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=998244353;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
set<int>Q;
priority_queue<pair<int,int> >P;
int e[35],a[N],l[N],r[N];
int siz,root[N],tr[35*N][2],sum[35*N];
int add(int x,int z) {
int i,t,y,ret=siz+1;
y=++siz;sum[y]=sum[x]+1;
for (i=31;i>=0;i--) {
t=(z&e[i])>>i;
tr[y][0]=tr[x][0];tr[y][1]=tr[x][1];
tr[y][t]=++siz;y=tr[y][t];
x=tr[x][t];sum[y]=sum[x]+1;
}
return ret;
}
int query(int x,int y,int z) {
int i,t,ret=0;
for (i=31;i>=0;i--) {
t=(z&e[i])>>i;
if (sum[tr[y][t^1]]>sum[tr[x][t^1]]) {
ret+=e[i];x=tr[x][t^1];y=tr[y][t^1];
} else { x=tr[x][t];y=tr[y][t]; }
}
return ret;
}
int main()
{
int i,n,ans=0;
scanf("%d", &n);
e[0]=1;for (i=1;i<35;i++) e[i]=2*e[i-1];
for (i=1;i<=n;i++) {
scanf("%d", &a[i]);P.push(make_pair(a[i],i));
}
for (i=1;i<=n;i++) root[i]=add(root[i-1],a[i]);
pair<int,int>kk;
set<int>::iterator it,is;
while (!P.empty()) {
kk=P.top();P.pop();
Q.insert(kk.second);
it=is=Q.find(kk.second);
if (is!=Q.begin()) {
is--;
if (is!=Q.begin()) {
is--;l[kk.second]=*is;
} else l[kk.second]=0;
} else l[kk.second]=0;
is=it;is++;
if (is!=Q.end()) {
is++;
if (is!=Q.end()) {
r[kk.second]=*is;
} else r[kk.second]=n+1;
} else r[kk.second]=n+1;
}
for (i=1;i<=n;i++) ans=max(ans,query(root[l[i]],root[r[i]-1],a[i]));
printf("%d\n", ans);
return 0;
}