F. Bits And Pieces(高妙的记忆化dp)

传送门

题意

n n n个数 a i a_i ai,找到满足 i < j < k i<j<k i<j<k的三元组最大化 a i ∣ ( a j & a k ) a_i|(a_j\& a_k) ai(aj&ak)

其中 n < 1 e 6 n<1e6 n<1e6


毫无头绪的样子…

动态维护数组 f [ m a s k ] f[mask] f[mask]表示有 f [ m a s k ] f[mask] f[mask]个数的子集是 m a s k mask mask

那么只要 f [ m a s k ] > = 2 f[mask]>=2 f[mask]>=2说明存在 a j & a k a_j\& a_k aj&ak m a s k mask mask

从后往前枚举 a i a_i ai,然后去贪心的选择 a j & a k a_j\&a_k aj&ak

具体来说从最高位往低位看,如果 a i a_i ai在当前位为零,那么就看下是否能把这一位选上

那么现在的难点是如何动态维护 f [ m a s k ] f[mask] f[mask]

如果对每个数去枚举子集的话太慢了,我们直接去从高位往低位递归所有子集

如果当前的 f [ x ] f[x] f[x]大于 2 2 2了说明不需要往下了,下面都是 x x x的子集,一定也都大于 2 2 2

否则,一直递归到底部,然后 f [ x ] + + f[x]++ f[x]++

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1<<22;
int a[maxn],ans,f[maxn],n,vis[maxn];
void pushdown(int x,int bit)
{
	if( f[x]>=2 )	return;
	if( bit==-1 )	{ f[x]++; return; }
	pushdown(x,bit-1);//这一位不剥削
	if( x&(1<<bit) )	pushdown(x^(1<<bit),bit-1);//剥削这一位 
} 
int get(int x)
{
	int ans = 0;
	for(int i=20;i>=0;i--)
		if( (x&(1<<i))==0&&f[ans|(1<<i)]>=2 )	ans |= (1<<i);
	return ans|x;
}
int main()
{
	cin >> n;
	for(int i=1;i<=n;i++)	scanf("%d",&a[i] );
	for(int i=n;i>=1;i-- )
	{
		if( i<=n-2 )	ans = max( ans,get( a[i] ) );
		pushdown( a[i],20 );
	}
	printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值