E. Iva & Pav -前缀和 + 二分 +位运算

题面

分析:

赛时一直纠结于与运算前缀和不可逆,导致没有思路,但是发现行不通并没有及时思考别的解决办法导致一条路走到黑,阻碍了自己的思维,在今年的网络赛赛时也是一样,行不通的时候就没心思去重新想其他方法,这是大忌,以后要改,必须能够赛时不断发散自己思维,思考多种解决办法,还有就是赛时遇到一些自我感觉麻烦的做法就认为对的可能性不大,就不再去想,要大胆思考各种方法,多尝试。
虽然与运算不可逆,但是拆开他的每一位,从前向后记录他的每一位的1的个数,这样就可以进行前缀和计算了,根据后来的查询,只需要查询区间内的每一位的1的个数,只要区间内每一个数的二进制表示下第 i i i位都是1,那么区间的与运算之和的第 i i i位也就一定是1,这样就可以求出区间与运算的和,进而二分解决。

代码

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

const int N = 2e5 + 10;

int a[N][32];
int n;
int L;
int k;

 bool check(int mid) {
    int cnt = 0;
    for(int i = 0; i <= 31; i ++) {
        //cout << a[mid][i] << ' ';
        if(a[mid][i] - a[L - 1][i] == mid - L + 1) cnt |= (1 << i);
    }
//   cout << mid << ' ' << cnt << endl;
    return cnt >= k;
 }

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    while(T --) {
        cin >> n;
        for(int i = 1; i <= n; i ++) {
            int x;
            cin >> x;
            for(int j = 0; j <= 31; j ++) {
                a[i][j] = a[i - 1][j] + (x >> j & 1);
            }
        }
        int q;
        cin >> q;
        while(q --) {
            cin >> L >> k;
            int l = L - 1;
            int r = n;
            while(l < r) {
                int mid = l + r + 1 >> 1;
                if(check(mid)) l = mid;
                else r = mid - 1;
            }
            if(l < L || l > n) cout << "-1 ";
            else cout << l << " ";
            //cout << endl;
        }
        cout << "\n";
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值