HihoCoder - 1496:尋找最大值(高維字首和||手動求子集)
阿新 • • 發佈:2018-11-13
描述
給定N個數A1, A2, A3, ... AN,小Ho想從中找到兩個數Ai和Aj(i ≠ j)使得乘積Ai × Aj × (Ai AND Aj)最大。其中AND是按位與操作。
小Ho當然知道怎麼做。現在他想把這個問題交給你。
輸入
第一行一個數T,表示資料組數。(1 <= T <= 10)
對於每一組資料:
第一行一個整數N(1<=N<=100,000)
第二行N個整數A1, A2, A3, ... AN (0 <= Ai <220)
輸出
一個數表示答案
樣例輸入
2 3 1 2 3 4 1 2 4 5
樣例輸出
12 80
思路:Ai*Aj*(Ai&Aj)我們列舉第三部分,假設第三部分為x=Ai&Aj,然後我們取x的超集的最大值和次大值即可。
對於每個Ai我們可以列舉子集,用Ai取更新子集的最大次大值。4777ms;
#include<bits/stdc++.h> using namespace std; const int maxn=(1<<20)+10; int Mx[maxn],Se[maxn]; long long ans; int main() {int T,N,x; scanf("%d",&T); while(T--){ memset(Mx,0,sizeof(Mx)); memset(Se,0,sizeof(Se)); scanf("%d",&N); for(int i=1;i<=N;i++){ scanf("%d",&x); for(int j=x;j;j=(j-1)&x){ if(x>Mx[j]){ Se[j]=Mx[j]; Mx[j]=x; } else if(x>Se[j]) Se[j]=x; } } ans=0; for(int i=1;i<maxn;i++) ans=max(ans,(long long)i*Mx[i]*Se[i]); printf("%lld\n",ans); } return 0; }
也可以利用高維字首和來維護最大次大值。1586ms。
(目前見到的三種:高維字首和維護了X集之和,位置的最小值,最大次大值。ORZ
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1<<20; int Mx[maxn+10],Se[maxn+10]; ll ans; int main() { int T,N,x; scanf("%d",&T); while(T--){ memset(Mx,0,sizeof(Mx)); memset(Se,0,sizeof(Se)); scanf("%d",&N); for(int i=1;i<=N;i++){ scanf("%d",&x); if(x>Mx[x]) Mx[x]=x; else Se[x]=x; } for(int i=0;i<20;i++){ for(int j=0;j<maxn;j++){ if(!(j&(1<<i))){ if(Mx[j|(1<<i)]>=Mx[j]){ Se[j]=max(Mx[j],Se[j|(1<<i)]); Mx[j]=Mx[j|(1<<i)]; } else Se[j]=max(Mx[j|(1<<i)],Se[j]); } } } ans=0; for(int i=1;i<maxn;i++) ans=max(ans,(ll)i*Mx[i]*Se[i]); printf("%lld\n",ans); } return 0; }