Manthan, Codefest 19 (open for everyone, rated, Div. 1 + Div. 2) F. Bits And Pieces sosdp

F. Bits And Pieces

题面

You are given an array ? of ? integers.

You need to find the maximum value of ??|(??&??) over all triplets (?,?,?) such that ?<?<?.

Here & denotes the bitwise AND operation, and | denotes the bitwise OR operation.

Input

The first line of input contains the integer ? (3≤?≤106), the size of the array ?.

Next line contains ? space separated integers ?1, ?2, ..., ?? (0≤??≤2⋅106), representing the elements of the array ?.

Output

Output a single integer, the maximum value of the expression given in the statement.

Examples

input

3
2 4 6

output

6

input

4
2 8 4 7

output

12

Note

In the first example, the only possible triplet is (1,2,3). Hence, the answer is 2|(4&6)=6.

In the second example, there are 4 possible triplets:

(1,2,3), value of which is 2|(8&4)=2.
(1,2,4), value of which is 2|(8&7)=2.
(1,3,4), value of which is 2|(4&7)=6.
(2,3,4), value of which is 8|(4&7)=12.
The maximum value hence is 12.

题意

给你n个数,然后让你找到三个不同的ijk,使得a[i]|(a[j]&a[k])最大

题解

比较显然的做法是枚举a[i],然后从高位到地位看最大的(a[j]&a[k])是多少。

(a[j]&a[k])这个东西我们单独维护,枚举a[j]的每一位,举个例子比如a[j]是10001,那么我们让cnt[10000],cnt[10001],cnt[00001]都加1;比如00101,我们让cnt[00100]和cnt[00001],cnt[00101]都加上1。

然后我们从高位到地位for循环贪心找到cnt[x]>2的最大的即可。

这个枚举可以用sosdp来做;也可以比较牛逼的操作每一位来枚举,见解法1。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=4000005;
int n,cnt[N],ans,a[N];
void insert(int x,int y){
    if (cnt[x|y]==2)return;
    if (x==0){
        cnt[y]++;
        return;
    }
    insert(x&x-1,y|x&-x);
    insert(x&x-1,y);
    // x&x-1是取消最小的一位,x&-x是取最小的一位
}
int main() {
    scanf("%d",&n);
    for (int i=1;i<=n;i++)scanf("%d",&a[i]);
    for (int i=n;i>=1;i--){
        if (i+2<=n){
            int now=0;
            for (int j=20;j>=0;j--)
                if (!((1<<j)&a[i])&&cnt[now|1<<j]==2)now|=1<<j;
            ans=max(ans,now|a[i]);
        }
        insert(a[i],0);
    }
    printf("%d\n",ans);
    return 0;
}

/* sos dp
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1<<21;
int dp[maxn][21],a[maxn],n;
void sosdp(int num,int k){
    if(k>20)return;
    if(dp[num][k]>1)return;
    dp[num][k]++;
    sosdp(num,k+1);
    if(num>>k&1){
        sosdp(num^(1<<k),k);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int ans = 0;
    for(int i=n;i>=1;i--){
        int res = 0, t = 0;
        for(int j=20;j>=0;j--){
            if(a[i]>>j&1){
                res|=1<<j;
            }else if(dp[t|(1<<j)][20]>1){
                res|=1<<j;
                t|=1<<j;
            }
        }
        sosdp(a[i],0);
        if(i<=n-2){
            ans=max(ans,res);
        }
    }
    cout<<ans<<endl;
}
*/

转载于:https://www.cnblogs.com/qscqesze/p/11453052.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值