Solution
首先答案可以转化成
A
n
s
k
=
m
i
n
i
<
=
k
m
i
n
a
,
b
,
a
∣
b
=
i
,
a
!
=
b
A
[
a
]
+
A
[
b
]
Ans_{k}=min_{i<=k}min_{a,b,a|b=i,a!=b}A[a]+A[b]
Ansk=mini<=kmina,b,a∣b=i,a!=bA[a]+A[b]
其实这东西就像
F
M
T
FMT
FMT
而
F
M
T
FMT
FMT有实际上是在
d
p
dp
dp
设
f
[
i
]
[
j
]
[
2
]
f[i][j][2]
f[i][j][2]表示
(
k
∣
i
=
i
)
A
[
k
]
(k|i=i)A[k]
(k∣i=i)A[k]的最小值和次小值(这个题可以记录位置)
当然还有另一个限制条件就是,数字k的二进制下前
j
j
j位随便,后面的几位必须和
i
i
i一样
显然
f
[
i
]
[
n
]
[
1
]
+
f
[
i
]
[
n
]
[
0
]
=
m
i
n
a
,
b
,
a
∣
b
=
i
,
a
!
=
b
A
[
a
]
+
A
[
b
]
f[i][n][1]+f[i][n][0]=min_{a,b,a|b=i,a!=b}A[a]+A[b]
f[i][n][1]+f[i][n][0]=mina,b,a∣b=i,a!=bA[a]+A[b]
然后考虑怎么把这个东西求出来
如果数字
i
i
i的第
j
j
j位是
0
0
0那么
f
[
i
]
[
j
−
1
]
−
>
f
[
i
]
[
j
]
f[i][j-1]->f[i][j]
f[i][j−1]−>f[i][j]
否则
f
[
i
]
[
j
−
1
]
和
f
[
i
−
(
1
<
<
j
)
]
[
j
−
1
]
−
>
f
[
i
]
[
j
]
f[i][j-1]和f[i-(1<<j)][j-1]->f[i][j]
f[i][j−1]和f[i−(1<<j)][j−1]−>f[i][j]
因为对于第
j
j
j位
f
[
i
]
[
j
−
1
]
f[i][j-1]
f[i][j−1]考虑了第
j
j
j位一定取
1
1
1的情况,
f
[
i
−
(
1
<
<
j
)
]
[
j
−
1
]
f[i-(1<<j)][j-1]
f[i−(1<<j)][j−1]考虑了第
j
j
j位一定取
0
0
0的情况。
合并怎么方便怎么来好了。
#include<bits/stdc++.h>
using namespace std;
int read(){
int rt=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){rt=rt*10+ch-'0';ch=getchar();}
return rt;
}
int n,a[1<<18];
struct _{
int v[2];
}data[1<<18];
bool cmp(int x,int y){
return a[x]<a[y];
}
_ Merge(_ x,_ y){
_ ret;
ret.v[0]=ret.v[1]=-1;
int buf[5],tot=0;
for(int i=0;i<2;i++)
if(x.v[i]!=-1){
buf[++tot]=x.v[i];
}
for(int i=0;i<2;i++){
if(y.v[i]!=-1){
buf[++tot]=y.v[i];
}
}
sort(buf+1,buf+1+tot);
tot=unique(buf+1,buf+1+tot)-buf-1;
sort(buf+1,buf+1+tot,cmp);
for(int i=0;i<2;i++){
if(tot>0){
ret.v[i]=buf[tot--];
}
}
return ret;
}
int main(){
n=read();
int m=n;
n=(1<<n);
for(int i=0;i<n;i++){
a[i]=read();
data[i].v[0]=i;
data[i].v[1]=-1;
}
for(int i=0;i<m;i++){
for(int j=n-1;j>=0;j--){
if(j&(1<<i)){
data[j]=Merge(data[j],data[j^(1<<i)]);
}
}
}
int ans = 0;
for(int i=1;i<n;i++){
if(data[i].v[0]+1 && data[i].v[1]+1){
ans = max(ans,a[data[i].v[0]]+a[data[i].v[1]]);
}
printf("%d\n",ans);
}
return 0;
}