LINK

考虑对每个 [ 1 , i ] [1,i] [1,i]建立一颗 01 T i r e \rm 01Tire 01Tire

那么我们就可以利用前缀和 O ( 1 ) O(1) O(1)得到区间 [ l , r ] [l,r] [l,r] T i r e \rm Tire Tire

在树上从高位往低位 d f s dfs dfs爆搜两个数每一位选 0 0 0还是选 1 1 1

设两个数分别走到树上的节点 l e \rm le le r e \rm re re

①.若 l e le le能走到 0 0 0 r e re re能走到 1 1 1就去搜

②.若 l e le le能走到 1 1 1 r e re re能走到 0 0 0就去搜

③.若 l e , r e le,re le,re能同时走到 0 0 0就去搜

④.若 l e , r e le,re le,re能同时走到 1 1 1就去搜

乍一看每一层有四种选择,总体复杂度似乎是 4 11 4^{11} 411

然而如果执行过①②,说明①②产生的答案一定比③④优秀

因为包含高位一,所以不可能同时执行,单词复杂度降到 2 11 2^{11} 211

注意

T i r e \rm Tire Tire树空间要开到 2 12 2^{12} 212

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5009;
int n,m,a[maxn],ans;
int zi[maxn][1<<12][2],id,val[maxn][1<<12],ID[maxn];
void insert(int id,int x)
{
	int now = 0;//当前的序号 
	for(int i=10;i>=0;i--)
	{
		int ok = ((x>>i)&1);
		if( !zi[id][now][ok] )	zi[id][now][ok] = ++ID[id];
		now = zi[id][now][ok]; val[id][now]++;
	}
}
//le表示第一个数dfs到树上的点,re表示第二个数dfs到树上的点 
void dfs(int r,int le,int re,int deep,int res)
{
	if( deep==-1 ){ ans = max( ans,res ); return; }
	int le0 = val[r][ zi[r][le][0] ],	le1 = val[r][ zi[r][le][1] ];
	int re0 = val[r][ zi[r][re][0] ],	re1 = val[r][ zi[r][re][1] ];
	int flag = 0;
	if( le0 && re1 )
		dfs( r,zi[r][le][0],zi[r][re][1],deep-1,res|(1<<deep) ),flag = 1;
	if( le1 && re0 )
		dfs( r,zi[r][le][1],zi[r][re][0],deep-1,res|(1<<deep) ),flag = 1;
	if( flag )	return;
	if( le0 && re0 )
	{
		if( le!=re || le0>=2 )
			dfs( r,zi[r][le][0],zi[r][re][0],deep-1,res );
	}
	if( le1 && re1 )
	{
		if( le!=re || le1>=2 )
			dfs( r,zi[r][le][1],zi[r][re][1],deep-1,res );
	}
}
void solve(int l,int r)
{
	for(int i=1;i<=ID[r];i++)	val[r][i] -= val[l-1][i];
	ans = 0;
	dfs(r,0,0,10,0);
	printf("%d\n",ans );
	for(int i=1;i<=ID[r];i++)	val[r][i] += val[l-1][i];
}
int main()
{
	cin >> n >> m;
	for(int i=1;i<=n;i++)	scanf("%d",&a[i] );
	
	for(int i=1;i<=n;i++)
	for(int j=1;j<=i;j++)	
		insert( i,a[j] );
		
	while( m-- )
	{
		int l,r; scanf("%d%d",&l,&r);
		if( l==r )	cout << 0 << endl;
		else	solve( l,r );
	}
}

然后我发现我是个脑瘫,这就是个区间 d p dp dp

f [ i ] [ j ] = m a x ( f [ i + 1 ] [ j ] , f [ i ] [ j − 1 ] ) \rm f[i][j]=max(f[i+1][j],f[i][j-1]) f[i][j]=max(f[i+1][j],f[i][j1])

然后再和 a i ⊕ a j a_i\oplus a_j aiaj取个最大值就好了

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e3+10;
int n,m,a[maxn],f[maxn][maxn];
int main()
{
	cin >> n >> m;
	for(int i=1;i<=n;i++)	scanf("%d",&a[i] );
	for(int i=1;i<n;i++)	f[i][i+1] = a[i]^a[i+1];
	for(int l=3;l<=n;l++)
	for(int i=1;i+l-1<=n;i++)
	{
		int j = i+l-1;
		f[i][j] = max( f[i+1][j],f[i][j-1] );
		f[i][j] = max( f[i][j],a[i]^a[j] );
	}
	while( m-- )
	{
		int l,r; scanf("%d%d",&l,&r);
		printf("%d\n",f[l][r] );
	}
}