AtCoder Regular Contest 100 - E Or Plus Max

本文介绍了一种利用位运算优化的算法,解决给定2^n个整数序列中,对于每个K(1≤K≤2^N−1),寻找i和j使得i|j<=K时a[i]+a[j]的最大值问题。通过记录下标避免重复计算,实现高效求解。
题目描述
There is an integer sequence of length 2^N: A0,A1,…,A2^N−1. (Note that the sequence is 0-indexed.)
For every integer K satisfying 1≤K≤2^N−1, solve the following problem:
Let i and j be integers. Find the maximum value of Ai+Aj where 0≤i<j≤2^N−1 and (i or j)≤K. Here, or denotes the bitwise OR.
Constraints
1≤N≤18
1≤Ai≤10^9
All values in input are integers.

 

输入
Input is given from Standard Input in the following format:

N
A0 A1 … A2^N−1

 

输出
Print 2^N−1 lines. In the i-th line, print the answer of the problem above for K=i.

 

样例输入

2
1 2 3 1
样例输出
3
4
5

 

提示

For K=1, the only possible pair of i and j is (i,j)=(0,1), so the answer is A0+A1=1+2=3.

For K=2, the possible pairs of i and j are (i,j)=(0,1),(0,2). When (i,j)=(0,2), Ai+Aj=1+3=4. This is the maximum value, so the answer is 4.

For K=3, the possible pairs of i and j are (i,j)=(0,1),(0,2),(0,3),(1,2),(1,3),(2,3) . When (i,j)=(1,2), Ai+Aj=2+3=5. This is the maximum value, so the answer is 5.

 

题意:给2^n个数,对于每一个k(1≤K≤2^N−1),找到最大的a[i]+a[j],其中i|j<=k

思路:对于任一K1<K2,凡是满足i|j<=K1的答案一定满足i|j<=K2,所以对于每个K,只需寻找i|j=k中a[i]+a[j]的最大值。采用记录下标的形式来避免a[i]与a[j]重复。

 

#include "iostream"
#include "algorithm"
#include "set"
#include "vector"

using namespace std;
const int maxn = (1 << 18) + 100;

struct node {
    int max1, max2;
} maxx[maxn];
int s[maxn];

void fun(int a, node &b) {
    if (a == b.max2 || a == b.max1) return;
    if (s[b.max1] < s[a]) {
        swap(b.max1, b.max2);
        b.max1 = a;
    } else if (s[b.max2] < s[a]) {
        b.max2 = a;
    }
}

int main() {
    //freopen("input.txt", "r", stdin);
    int n;
    cin >> n;
    int nn = 1 << n;
    for (int i = 0; i < nn; i++) {
        cin >> s[i];
        maxx[i].max1 = i;
        maxx[i].max2 = nn;
    }
    for (int i = 1; i < nn; i++) {
        for (int j = 0; j < n; j++) {
            if (i & (1 << j)) {
                int k = i ^(1 << j);
                fun(maxx[k].max1, maxx[i]);
                fun(maxx[k].max2, maxx[i]);
            }
        }
    }
    int ans = 0;
    for (int i = 1; i < nn; i++) {
        ans = max(ans, s[maxx[i].max1] + s[maxx[i].max2]);
        printf("%d\n", ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/albert-biu/p/10062411.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值