3226. 【HBOI2013】ALO
Description
Welcome to ALO ( Arithmetic and Logistic Online)。这是一个VR MMORPG,如名字所见,到处充满了数学的谜题。
现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同。现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为ai, ai+1, …, aj,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值的最大值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密度为max{k xor ap | ap ≠ k , i ≤ p ≤ j}。
现在你需要知道你怎么选取需要融合的宝石,才能使生成的宝石能量密度最大。
Input
第一行,一个整数n,表示宝石个数。
第二行,n个整数,分别表示a1至an,表示每颗宝石的能量密度,保证对于i ≠ j有ai ≠ aj。
Output
输出一行一个整数,表示最大能生成的宝石能量密度。
Sample Input
5
9 2 1 4 7
Sample Output
14
Data Constraint
对于20%的数据有n ≤ 100。
对于50%的数据有n ≤ 2000。
对于100%的数据有1 ≤ n ≤ 50000, 0 ≤ ai ≤ 10^9。
Hint
样例解释:选择区间[1,5],最大值为7 xor 9。
Solution
题目大意
给定一个长度为n的数列,选定一个区间,以这个区间的次大值与区间内其他数异或,求最大值。
题解
我们可以先扫一遍,求出对于每一个位置
i
,在他前面比他大的两个最近的位置
然后,求区间
[l2[i]+1,r1[i]−1]
和
[l1[i]+1,r2[i]−1]
的最大值。这个可以用可持久化trie树来实现。
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;
#define N 50000 + 10
typedef long long ll ;
struct Trie {
int ch[2] , tot , id ;
} s[50*N] ;
int a[N] , l1[N] , l2[N] , r1[N] , r2[N] , root[N] ;
int n , T ;
ll ans ;
void ADD( int &po , ll va , ll dig ) {
s[++T] = s[po] ;
po = T ;
s[T].tot ++ ;
if ( dig < 0 ) {
s[T].id = va ;
return ;
}
int son = ( ( va >> dig ) & 1 ) ;
ADD( s[T].ch[son] , va , dig - 1 ) ;
}
void search( int l , int r , ll num , ll va , ll dig ) {
if ( dig < 0 ) {
ans = max( ans , num ) ;
return ;
}
int son = ! ( ( va >> dig ) & 1 ) ;
if ( s[s[r].ch[son]].tot - s[s[l].ch[son]].tot > 0 ) search( s[l].ch[son] , s[r].ch[son] , num + (1 << dig) , va , dig - 1 ) ;
else search( s[l].ch[!son] , s[r].ch[!son] , num , va , dig - 1 ) ;
}
int main() {
freopen( "ALO.in" , "r" , stdin ) ;
freopen( "ALO.out" , "w" , stdout ) ;
scanf( "%d" , &n ) ;
for(int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &a[i] ) ;
l2[1] = 0 ;
for (int i = 2 ; i <= n ; i ++ ) {
l2[i] = i - 1 ;
while ( l2[i] > 0 && a[l2[i]] < a[i] ) l2[i] = l2[l2[i]] ;
l1[i] = l2[i] - 1 ;
while ( l1[i] > 0 && a[l1[i]] < a[i] ) l1[i] = l2[l1[i]] ;
}
r1[n] = n + 1 ;
for (int i = n - 1 ; i >= 1 ; i -- ) {
r1[i] = i + 1 ;
while ( r1[i] <= n && a[r1[i]] < a[i] ) r1[i] = r1[r1[i]] ;
r2[i] = r1[i] + 1 ;
while ( r2[i] <= n && a[r2[i]] < a[i] ) r2[i] = r1[r2[i]] ;
}
for (int i = 1 ; i <= n ; i ++ )
ADD( root[i] = root[i-1] , a[i] , 32 ) ;
for (int i = 1 ; i <= n ; i ++ ) {
if ( l1[i] >= 0 && r1[i] <= n + 1 ) {
search( root[l1[i]] , root[r1[i] - 1] , 0 , (ll)a[i] , 32 ) ;
}
if ( l2[i] >= 0 && r2[i] <= n + 1 ) {
search( root[l2[i]] , root[r2[i] - 1] , 0 , (ll)a[i] , 32 ) ;
}
}
printf( "%I64d\n" , ans ) ;
return 0 ;
}
以上.