題目
給定n(n<=18),長度爲的數組a[],,1<=ai<=1e9
對於每個, 求滿足的ai+aj的最大值
思路來源
https://www.cnblogs.com/heyuhhh/p/11585358.html
題解
(i or j)<=k,很不好做,
考慮轉化成(i or j)==k再做前綴和,發現也很難做
於是考慮(i or j)是k的子集,對k統計k的子集中的top2,
再做一遍前綴和,這樣,
統計用k的子集更新k的答案,再用k-1的子集,...,1的子集更新k的答案
於是就變成了先高維前綴和保存top2,然後再前綴和更新一遍答案
代碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=19,M=1<<N;
#define fi first
#define se second
typedef pair<int,int> P;
int n,v,ans[M];
P dp[M];
void merge(P &a,int x){
if(x>=a.fi){
a.se=a.fi;
a.fi=x;
}
else if(x>a.se){
a.se=x;
}
}
int main(){
scanf("%d",&n);
dp[0]=P(-1,-1);
for(int i=0;i<(1<<n);++i){
scanf("%d",&v);
dp[i]=P(v,-1);
}
for(int i=0;i<n;++i){
for(int j=0;j<(1<<n);++j){
if(j>>i&1){//去掉1位的子集
merge(dp[j],dp[j^(1<<i)].fi);
merge(dp[j],dp[j^(1<<i)].se);
}
}
}
for(int j=1;j<(1<<n);++j){
ans[j]=dp[j].fi+dp[j].se;
ans[j]=max(ans[j],ans[j-1]);
printf("%d\n",ans[j]);
}
return 0;
}