arc_100E Or Plus Max

传送门
在这里插入图片描述


Solution

首先答案可以转化成
A n s k = m i n i &lt; = k m i n a , b , a ∣ b = i , a ! = b A [ a ] + A [ b ] Ans_{k}=min_{i&lt;=k}min_{a,b,a|b=i,a!=b}A[a]+A[b] Ansk=mini<=kmina,b,ab=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] (ki=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,ab=i,a!=bA[a]+A[b]
然后考虑怎么把这个东西求出来
如果数字 i i i的第 j j j位是 0 0 0那么 f [ i ] [ j − 1 ] − &gt; f [ i ] [ j ] f[i][j-1]-&gt;f[i][j] f[i][j1]>f[i][j]
否则
f [ i ] [ j − 1 ] 和 f [ i − ( 1 &lt; &lt; j ) ] [ j − 1 ] − &gt; f [ i ] [ j ] f[i][j-1]和f[i-(1&lt;&lt;j)][j-1]-&gt;f[i][j] f[i][j1]f[i(1<<j)][j1]>f[i][j]
因为对于第 j j j f [ i ] [ j − 1 ] f[i][j-1] f[i][j1]考虑了第 j j j位一定取 1 1 1的情况, f [ i − ( 1 &lt; &lt; j ) ] [ j − 1 ] f[i-(1&lt;&lt;j)][j-1] f[i(1<<j)][j1]考虑了第 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值