hihocoder 1496 寻找最大值(高维前缀最大次大值)

 

【题目链接】 https://hihocoder.com/problemset/problem/1496

 

【题目大意】

  给定N个数A1, A2, A3, ... AN,
  从中找到两个数Ai和Aj(i≠j)使得乘积Ai*Aj*(Ai&Aj)最大

 

【题解】

  我们可以枚举x&y的结果z,找出两个数x&y==z使得x*y最大,更新答案即可,
  条件可以被削弱为z为x&y的子集,这种条件放缩不会导致最优解的丢失,
  z为x&y的子集等价于z为x的子集并且z为y的子集。
  那么我们只要找出以z为子集的最大值和次大值,然后枚举z即可计算出答案。
  复杂度O(k*2^k).

 

【代码】

#include <cstdio>
#include <algorithm>
using namespace std;
struct data{
    int val[2];
    data operator +(const data &rhs)const{
        int t_val[2]={val[0],val[1]};
        for(int i=0;i<2;i++){
            if(rhs.val[i]>t_val[0]){
                t_val[1]=t_val[0];
                t_val[0]=rhs.val[i];
            }else if(rhs.val[i]>t_val[1])t_val[1]=rhs.val[i];
        }return data{t_val[0],t_val[1]};
    }
}dp[(1<<20)+10];
int T,n;
int main(){
    scanf("%d",&T);
    int all=1<<20;
    while(T--){
        for(int i=0;i<all;i++)dp[i]=data{0,0};
        scanf("%d",&n);
        for(int i=1,x;i<=n;i++){
            scanf("%d",&x);
            dp[x]=dp[x]+data{x,0};
        } 
        for(int i=0;i<20;i++)
            for(int j=0;j<all;j++)
                if(~j&(1<<i))dp[j]=dp[j]+dp[j|(1<<i)];
        long long ans=0;
        for(int i=0;i<all;i++)ans=max(ans,1LL*i*dp[i].val[0]*dp[i].val[1]);
        printf("%lld\n",ans);
    }return 0;
}
posted @ 2017-04-05 00:06  forever97  阅读(842)  评论(0编辑  收藏  举报