算法 {二进制与&}

算法 {二进制与&}

与&

性质

@MARK_2;
对于数组A[1,2,3,...,N] (每个元素是[0, 2^31]范围), 令一个数组的价值为所有元素的与&运算的结果; 那么所有以A[N]为结尾的子数组(有N个), 这些子数组 他们的价值 最多只有32种可能;
.对于所有的i=[1-N]: | Set{ Val( A[i - N] ) } | <= 32;
证明: 当i==N时, 假设A[N]二进制有X个1, &and: A[i...N]的&结果, 那么随着你i --往左移动, 此时的A[i-N]的结果 要么等于&and 要么是将&and里的若干个1给变成了0; 即最初A[N]有X个1, 那么其实所有子数组的价值 最多只有X个取值;
. 不要以为是X个1的选与不选, 这是错误的; 比如当i==Nand = A[N] = 100110, 然后当i == N-1时 可能and = 100100, 然后i == N-2 可能and = 000100, 然后i == N-3 可能and = 000000, 于是对于i <= N-3and == 000000;

那么对于A[r],我们如何得到所有A[l]&...&A[r]的值呢?(最多只有30个)
cur = A[r]开始,比如A[r] = 10010[1],[4]位是1,因为只有遇到[1]/[4]0的数 那么这个数cur会变小, 因此我们计算[1]/[4]位是0的 且下标<r的最大下标, 然后找最大值 比如[l] (这说明A[l+1]&...&A[r] == A[r]), 于是更新cur &= A[l];

vector<int> Ind[ 32];
int N = A.size();
FOR_( i, 0, N-1){
    FOR_( bit, 0, 30){
        if( (A[i]>>bit) & 1){}
        else{
            Ind[ bit].push_back( i);
        }
    }
}
int ANS = 1e9;
FOR_( i, 0, N-1){
    for( auto cur = A[i], ind = i;;){
        ANS = std::min( ANS, std::abs( cur - K));
        int nex = -1;
        FOR_( bit, 0, 30){
            if( (cur>>bit) & 1){
                auto it = std::lower_bound( Ind[bit].begin(), Ind[bit].end(), ind);
                if( it == Ind[bit].begin()){ continue;}
                it = std::prev( it);
                nex = std::max( nex, *it);
            }
        }
        if( nex == -1){ break;}
        cur &= A[nex];
        ind = nex;
    }
}
return ANS;

. 例题: @LINK: https://leetcode.cn/problems/find-subarray-with-bitwise-and-closest-to-k/description/;

@DELI;

-1 & x = x;
因为-1 == 二进制全1, 所以x有1 结果是1, 有0 结果是0;

应用

@LINK: https://editor.csdn.net/md/?articleId=137481450;
只要有0, 结果就是0;

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值