F - Bits And Pieces

F - Bits And Pieces

Something about SOS dp

  1. codeforces
  2. 我的翻译

题意:给定序列a,求
m a x ( a i ∣ ( a j & a k ) ) 1 ≤ i < j < k ≤ n max(a_i |(a_j\&a_k))1\leq i < j <k \leq n max(ai(aj&ak))1i<j<kn
分析: 对于位运算求最大值的题目,一般采用从最高位向最低位依次填充贪心的做法。
分析 ∣ | & \& &的性质,可以知道, 可以枚举 a i a_i ai,然后从最高位贪心,判断有一个bit位 a j , a k a_j,a_k aj,ak存在两个数位1就可以继续放,问题在于我们怎么保证第一次取一个bit位的有一些集合 s s s满足条件,下一次取从 s s s这个集合中取,而不是其它不符合条件中取。这种就是经典的SOSdp,SOSdp求的是
∑ m a s k & i = i B [ i ] \sum_{mask\&i = i}B[i] mask&i=iB[i]B[i]是指值为i的 a a a的个数
本题求得是
∑ m a s k & i = m a s k B [ i ] \sum_{mask\&i=mask}B[i] mask&i=maskB[i]
只需要将sosdp的状态转移反过来就OK了


const int maxn = 1e6+10;
int a[maxn];
int dp[1<<21][21];
 
void update(int num,int k){
	if(k > 20) return ;
	if(dp[num][k] > 1) return ;
	++dp[num][k];
	update(num,k+1);
	if(num>>k&1)
		update(num^(1<<k),k);
}
int main(void)
{
	ios::sync_with_stdio(false);
	cin.tie(0);
    int n;cin>>n;
    for(int i = 1;i <= n; ++i)
    	cin>>a[i];
    int ans = 0;
    for(int i = n;i >= 1; --i){
    	int res = 0;
    	int t = 0;
    	for(int j = 20;j >= 0; --j){
    		if(a[i]>>j&1)
    			res |= 1<<j;
    		else if(dp[t|(1<<j)][20] > 1)
    			res |= 1<<j,t |= 1<<j;
    	}
    	update(a[i],0);
    	if(i <= n-2)
    		ans = max(ans,res);
    }
    cout<<ans<<endl;
   return 0;
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值