AtCoder Regular Contest 100 E - Or Plus Max
思路:
不难发现,这个答案是递增的,对于每个集合,在转移的时候,我们是从小集合转移到大集合,因为小集合能满足的条件,大集合也一定能够满足。
一共有\(2^n\)个结果,对于第i个结果,是由 \([1,i]\) 转移而来,也就是说,在 \([1,i]\) 中选取两个数x,y
满足\(a_x | a_y<=k且使得(a_x+a_y)最大\)
对于第i个数的答案可以开一个pair存满足条件下最大x和次大y的下标,如果暂时没法找到次大,先暂时赋值为-1
变量 num 是 i 的一个子集,也就是上述说的从小集合转移大集合,我们把i的所有子集的存下来,(这里不应该表诉为i的所有子集,而是应该说所有子集中较大的前n个,因为较大的子集对答案的贡献始终优于较小的,所以选取前n个即可,也就是单独把每一位的0抹掉)按权值降序,选前两个
atc给的英文题解
#include<bits/stdc++.h>
#define de cout<<"---"<<endl;
#define int long long
#define ll long long
#define endl '\n'
using namespace std;
const ll inf =0x3f3f3f3f3f;
const ll mod =1e9+7;//998244853
const int N=2e6+7;
ll qpow(ll a,ll p){if(p<1)p+=mod-1;ll ans=1;while(p){if(p&1)ans=ans*a%mod;a=a*a%mod;p>>=1;}return ans%mod;}
int n,m;
int a[N];
vector<int>v;
pair<int,int>p[N];
bool cmp(int x,int y){
return a[x]>a[y];
}
void solve(){
cin>>n;
for(int i=0;i<(1<<n);i++){
cin>>a[i];
}
for(int i=0;i<(1<<n);i++){
v.clear();
v.push_back(i);
int f=0;
for(int j=n-1;j>=0;j--){
if((i>>j)&1){
int num=i^(1<<j);
v.push_back(p[num].first);
if(p[num].second!=-1){
v.push_back(p[num].second);
}
f++;
//if(f==3)break;
}
}
sort(v.begin(),v.end(),cmp);
v.erase(unique(v.begin(),v.end()),v.end());
if(v.size()==1){
p[i]={v[0],-1};
}
else {
p[i]={v[0],v[1]};
}
}
ll ans=-inf;
for(int i=1;i<(1<<n);i++){
ans=max(ans,a[p[i].first]+a[p[i].second]);
cout<<ans<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int kase=1;
//cin>>kase;
while(kase--){solve();}
}