E - Or Plus Max
Time limit : 2sec / Memory limit : 1024MB
Score : 700 points
Problem Statement
There is an integer sequence of length 2N: A0,A1,…,A2N−1. (Note that the sequence is 0-indexed.)
For every integer K satisfying 1≤K≤2N−1, solve the following problem:
- Let i and j be integers. Find the maximum value of Ai+Aj where 0≤i<j≤2N−1 and (i or j)≤K. Here, or denotes the bitwise OR.
Constraints
- 1≤N≤18
- 1≤Ai≤109
- All values in input are integers.
Input
Input is given from Standard Input in the following format:
N A0 A1 … A2N−1
Output
Print 2N−1 lines. In the i-th line, print the answer of the problem above for K=i.
Sample Input 1
2 1 2 3 1
Sample Output 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.
Sample Input 2
3 10 71 84 33 6 47 23 25
Sample Output 2
81 94 155 155 155 155 155
Sample Input 3
4 75 26 45 72 81 47 97 97 2 2 25 82 84 17 56 32
Sample Output 3
101 120 147 156 156 178 194 194 194 194 194 194 194 194 194
思路:或之值<=k,显然也满足<=k-1,那么只需要考虑或之值=k的就行,因为<k的可以有k-1推出来。那么显然问题变成找出k的二进制中两个子集(i和j)相加的和最大,这里子集意思是i or j or k = k且i不等于j。那么怎么算呢?比如k(2) = 1011,那么我们轮流将其中的某个1换成0,从得出新的那个数转移两个值过来,即维护最大的两个值,就能做到不缺漏了。复杂度O(N*2^N)
# include <bits/stdc++.h>
# define A first
# define B second
# define PII pair<int,int>
using namespace std;
const int maxn = 1<<18;
int a[maxn+3];
PII imax[maxn];
void fun(int x, PII &y)
{
if(x == y.A || x == y.B) return;
if(a[x] > a[y.A]) y.B = y.A,y.A = x;
else if(a[x] > a[y.B]) y.B=x;
}
int main()
{
int N, n, ans=0;
scanf("%d",&n);
N = 1<<n;
a[N] = 0;
for(int i=0; i<N; ++i) scanf("%d",&a[i]), imax[i].A=i, imax[i].B=N;
for(int i=1; i<N; ++i)
{
for(int j=0; j<n; ++j)
{
if(i&(1<<j))
{
int k=i^(1<<j);
fun(imax[k].A, imax[i]);
fun(imax[k].B, imax[i]);
}
}
}
for(int i=1; i<N; ++i)
{
ans = max(ans, a[imax[i].A]+a[imax[i].B]);
printf("%d\n",ans);
}
return 0;
}