[ARC100E] Or Plus Max 题解

题目来源

Description

给你一个长度为 2 n 2^n 2n 的序列 a a a,对于每个 1 ≤ k < 2 n 1\le k<2^n 1k<2n,找出最大的 a i + a j a_i+a_j ai+aj,其中 i ∨ j ≤ k i\vee j\le k ijk 0 ≤ i < j < 2 n 0\le i<j<2^n 0i<j<2n

  • 1 ≤ n ≤ 18 , 1 ≤ a i ≤ 1 0 9 1\le n\le18,1\le a_i\le10^9 1n18,1ai109

Solution

若把二进制数看为一个集合,则我们称二进制数 a ⊆ b a\subseteq b ab,表示二进制数 b b b 的每一位 0 0 0 a a a 中均为 0 0 0(例如: 1010 1 2 ⊆ 1110 1 2 10101_2\subseteq11101_2 101012111012,但 1010 1 2 ⊈ 1100 1 2 10101_2\not\subseteq11001_2 101012110012)。

那么, i , j ⊆ k i,j\subseteq k i,jk 的必要条件为 i ∨ j = k i\vee j=k ij=k,充分条件为 i ∨ j ≤ k i\vee j\le k ijk

而由于我们要求的答案 a n s k = max ⁡ k 0 = 1 k { max ⁡ i ∨ j = k 0 , 0 ≤ i < j < 2 n { a i + a j } } ans_k=\max\limits_{k_0=1}^k\Big\{\max\limits_{i\vee j=k_0,0\le i<j<2^n}\{a_i+a_j\}\Big\} ansk=k0=1maxk{ij=k0,0i<j<2nmax{ai+aj}},则可以将其转化为求 max ⁡ i , j ⊆ k , 0 ≤ i , j < 2 n { a i + a j } \max\limits_{i,j\subseteq k,0\le i,j<2^n}\{a_i+a_j\} i,jk,0i,j<2nmax{ai+aj}

则我们可以考虑运用 SOSDP,设 f k f_k fk 存储满足 i , j ⊆ k , 0 ≤ i , j < 2 n i,j\subseteq k,0\le i,j<2^n i,jk,0i,j<2n a i + a j a_i+a_j ai+aj 的最大值和次大值,则实际上可以将其看作为 n n n 维的 DP 进行了状态压缩,每一维只有 0 / 1 0/1 0/1 两种取值。

因此,我们应当先枚举维数 j j j,再将每一个满足第 j j j 位为 1 1 1 i i i 进行转移(即 i ∧ 2 j = 1 i\wedge2^j=1 i2j=1 时, f i  xor  2 j → f i f_{i~\text{xor}~2^j}\to f_i fi xor 2jfi)。

Code

#include <bits/stdc++.h>
using namespace std;
int n,a[(1<<18)+5];
pair<int,int> f[(1<<18)+5]; // 存储最大&次大值 
pair<int,int> merge(pair<int,int> a,pair<int,int> b){
	pair<int,int> res;
	if (a.first>b.first) res.first=a.first,res.second=max(a.second,b.first);
	else res.first=b.first,res.second=max(b.second,a.first);
	return res;
}
int main(){
	scanf("%d",&n);
	for (int i=0;i<(1<<n);i++) scanf("%d",&a[i]),f[i]={a[i],0};
	for (int j=0;j<n;j++) // 维数 
		for (int i=1;i<(1<<n);i++)
			if ((i>>j)&1) f[i]=merge(f[i],f[i^(1<<j)]);
	int ans=0;
	for (int i=1;i<(1<<n);i++) ans=max(ans,f[i].first+f[i].second),printf("%d\n",ans);
	return 0;
}
  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值