​传送门​

题意

n n n个数 a i a_i ai,找到满足 i < j < k i<j<k i<j<k的三元组最大化 a i ∣ ( a j & a k ) a_i|(a_j\& a_k) ai∣(aj&ak)

其中 n < 1 e 6 n<1e6 n<1e6


毫无头绪的样子…

动态维护数组 f [ m a s k ] f[mask] f[mask]表示有 f [ m a s k ] f[mask] f[mask]个数的子集是 m a s k mask mask

那么只要 f [ m a s k ] > = 2 f[mask]>=2 f[mask]>=2说明存在 a j & a k a_j\& a_k aj&ak为 m a s k mask mask

从后往前枚举 a i a_i ai,然后去贪心的选择 a j & a k a_j\&a_k aj&ak

具体来说从最高位往低位看,如果 a i a_i ai在当前位为零,那么就看下是否能把这一位选上

那么现在的难点是如何动态维护 f [ m a s k ] f[mask] f[mask]

如果对每个数去枚举子集的话太慢了,我们直接去从高位往低位递归所有子集

如果当前的 f [ x ] f[x] f[x]大于 2 2 2了说明不需要往下了,下面都是 x x x的子集,一定也都大于 2 2 2

否则,一直递归到底部,然后 f [ x ] + + f[x]++ f[x]++

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1<<22;
int a[maxn],ans,f[maxn],n,vis[maxn];
void pushdown(int x,int bit)
{
if( f[x]>=2 ) return;
if( bit==-1 ) { f[x]++; return; }
pushdown(x,bit-1);//这一位不剥削
if( x&(1<<bit) ) pushdown(x^(1<<bit),bit-1);//剥削这一位
}
int get(int x)
{
int ans = 0;
for(int i=20;i>=0;i--)
if( (x&(1<<i))==0&&f[ans|(1<<i)]>=2 ) ans |= (1<<i);
return ans|x;
}
int main()
{
cin >> n;
for(int i=1;i<=n;i++) scanf("%d",&a[i] );
for(int i=n;i>=1;i-- )
{
if( i<=n-2 ) ans = max( ans,get( a[i] ) );
pushdown( a[i],20 );
}
printf("%d",ans);
}