题目大意
给定
n
个正整数的序列
op
可以是
xor,and,or
中的一个
求最大的
ai op aj (1≤i<j≤n)
T
组数据。
Data Constraint
题解
xor
操作显然是最简单的,直接在tire上贪心的跑一下。
or,and
相对复杂。先思考
and
操作。
考虑从高位向低位贪心,若当前位置是1,显然需要找到另一个数当前位是1。若是0,那么当前为是0/1的数都可能最优,所以不能在trie上跑。预处理数组
fx
表示在序列
a
中,有多少个数二进制下1的位置包含了
这个可以分治计算。
设当前分治的区间
[0,2x]
,在我们计算出左右子区间的贡献后,
fx=fx+fx+2x−1 , 0≤x≤2x−1
。这是因为包含了
x+2x−1
的必定也包含了
x
。
有了
or
同理。
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std ;
#define N 100000 + 10
#define M 2000000 + 10
const int MAXN = 20 ;
struct Trie {
int Son[2] ;
} T[MAXN*N] ;
int a[N] , f[M] ;
int Case , n , op , Cnt ;
int ans ;
inline int Read() {
int ret = 0 ;
char ch = getchar() ;
while ( ch < '0' || ch > '9' ) ch = getchar() ;
while ( ch >= '0' && ch <= '9' ) ret = ret * 10 + ch - '0' , ch = getchar() ;
return ret ;
}
inline int NewNode() {
Cnt ++ ;
T[Cnt].Son[0] = T[Cnt].Son[1] = 0 ;
return Cnt ;
}
void Insert( int x , int v , int dep ) {
if ( dep < 0 ) return ;
int w = (v >> dep) & 1 ;
if ( !T[x].Son[w] ) T[x].Son[w] = NewNode() ;
Insert( T[x].Son[w] , v , dep - 1 ) ;
}
void Search( int x , int v , int dep , int sum ) {
if ( dep < 0 ) { ans = max( ans , sum ) ; return ; }
int w = (v >> dep) & 1 ;
if ( T[x].Son[!w] ) Search( T[x].Son[!w] , v , dep - 1 , sum | (1 << dep) ) ;
else Search( T[x].Son[w] , v , dep - 1 , sum ) ;
}
void SolXOR() {
int UP = 20 ;
for (int i = n ; i >= 1 ; i -- ) {
Search( 1 , a[i] , UP , 0 ) ;
Insert( 1 , a[i] , UP ) ;
}
printf( "%d\n" , ans ) ;
}
void DIV( int l , int r , int w ) {
if ( l == r ) return ;
int mid = (l + r) / 2 ;
DIV( l , mid , w - 1 ) ;
DIV( mid + 1 , r , w - 1 ) ;
for (int i = l ; i <= mid ; i ++ ) f[i] += f[i+(1<<(w-1))] ;
}
void Pre() {
memset( f , 0 , sizeof(f) ) ;
for (int i = 1 ; i <= n ; i ++ ) f[a[i]] ++ ;
DIV( 0 , (1 << 20) - 1 , 20 ) ;
}
void SolAND() {
for (int i = 1 ; i <= n ; i ++ ) {
int sum = 0 ;
for (int k = 20 ; k >= 0 ; k -- ) {
int x = (a[i] >> k) & 1 ;
if ( !x ) continue ;
if ( f[sum|(1<<k)] > 1 ) sum |= 1 << k ;
}
ans = max( ans , sum ) ;
}
printf( "%d\n" , ans ) ;
}
void SolOR() {
for (int i = 1 ; i <= n ; i ++ ) {
int sum = 0 , bas = 0 ;
for (int k = 20 ; k >= 0 ; k -- ) {
int x = (a[i] >> k) & 1 ;
if ( x ) sum |= 1 << k ;
else {
if ( f[bas|(1<<k)] ) bas |= 1 << k , sum |= 1 << k ;
}
}
ans = max( ans , sum ) ;
}
printf( "%d\n" , ans ) ;
}
int main() {
freopen( "maximum.in" , "r" , stdin ) ;
freopen( "maximum.out" , "w" , stdout ) ;
scanf( "%d" , &Case ) ;
while ( Case -- ) {
T[1].Son[0] = T[1].Son[1] = 0 ;
Cnt = 1 , ans = 0 ;
n = Read() , op = Read() ;
for (int i = 1 ; i <= n ; i ++ ) a[i] = Read() ;
if ( op == 2 ) SolXOR() ;
else {
Pre() ;
if ( op == 1 ) SolAND() ;
else SolOR() ;
}
}
return 0 ;
}
以上.