AtCoder Regular Contest 100 E - Or Plus Max(高维前缀和sosdp)

题目

给定n(n<=18),长度为2^n的数组a[],a_{0},a_{1},\dots,a_{2^{n}-1},1<=ai<=1e9

对于每个k\epsilon [1,2^{n}-1], 求满足0\leq i<j\leq 2^{n}-1,(i|j)\leq k的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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值