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给的英文题解

image.png

#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();}
}
posted @ 2022-04-28 22:37  LiAnG24  阅读(54)  评论(0)    收藏  举报