题意:求 (maxlimits_{i<j<k}a_i|(a_j&a_k))。
(1leq n leq 10^6,1leq a_ileq 2 imes 10^6)
u1s1 这题算高维前缀和里不那么 sb 的题,虽然代码也很简单。
很容易想到一个贪心,从高到低枚举每一位,能填 (1) 就填 (1),不能填 (1) 就填 (0)。
于是本题转化为一个问题:是否存在某个 (i,j,k) 使得 (x) 为 (a_i|(a_j&a_k)) 的子集。枚举 (a_i) 包含 (x) 中的哪些位,然后贪心地取下标最小的 (i),以及下标最大的 (j,k),判断 (i<j) 即可。
至于怎样求下标最小的 (i) 和下标最大的 (j,k)。记 (mn_x) 为下标最小的包含 (x) 的 (a_i),(mx_x) 为下标最大的两个包含 (x) 的 (a_i)。高位前缀和随便一搞就行了。
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=1;
while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
x*=neg;
}
const int MAXN=1e6;
const int LOG_N=21;
const int LIM=(1<<LOG_N)-1;
int n,a[MAXN+5],tmp[4],mn[LIM+5];
pii mx[LIM+5];
pii merge(pii x,pii y){
tmp[0]=x.fi,tmp[1]=x.se,tmp[2]=y.fi,tmp[3]=y.se;
sort(tmp,tmp+4);reverse(tmp,tmp+4);return mp(tmp[0],tmp[1]);
}
bool check(int x){
for(int i=x;i;i=(i-1)&x) if(mn[x^i]<mx[i].se) return 1;
return (mn[x]<mx[0].se);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
memset(mn,63,sizeof(mn));
for(int i=1;i<=n;i++) mn[a[i]]=min(mn[a[i]],i);
for(int i=1;i<=n;i++) mx[a[i]]=merge(mx[a[i]],mp(i,0));
for(int i=0;i<LOG_N;i++) for(int j=LIM;~j;j--) if(!(j>>i&1)){
mn[j]=min(mn[j],mn[j^(1<<i)]);mx[j]=merge(mx[j],mx[j^(1<<i)]);
}
int cur=0;for(int i=LOG_N;~i;i--) if(check(cur|(1<<i))) cur|=(1<<i);
printf("%d
",cur);
return 0;
}
上帝不要惩罚我刷水题(