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; }
愿你出走半生,归来仍是少年