首页 > 其他分享 >从CF1878E学习前缀和维护二进制拆位分析思想

从CF1878E学习前缀和维护二进制拆位分析思想

时间:2024-01-22 15:55:37浏览次数:34  
标签:CF1878E 前缀 int pref mid 按位 include 拆位

Problem - 1878E - Codeforces

这题我想到了个大概,按位与的话结果肯定是递减的,而且要从二进制每一位下手,但是思路只停留在暴力对整个数操作。

当然,利用这个性质,肯定要二分。

拆位思想

比如要计算

1110001
1101110
0100010

我们知道最后结果肯定是留下都有 \(1\) 的位

0100000

但每次都进行按位与肯定是超时的,能不能把按位与前缀和两个思想结合应用呢?

对于上述的式子,我们可以拆位分析,具体地:

  • 对于三个按位与的七位二进制数,预处理出第 \(k(k \leq 7)\) 位在前 \(i(i\leq 3)\) 数中的数码\((0/1)\) 的前缀和。
  • 那么显然判断结果时,只要按位查询前缀和,等于三的就是 \(1\),否则是 \(0\)。

推广到 \(n\) 个 \(m\) 位的二进制数:

  • 维护一个前缀和数组 \(pref_{i, j}\) 表示前 \(i\) 个数,第 \(j\) 个数码的前缀和。
    • 如果第 \(i\) 个数的第 \(j\) 个数码是 \(1\),那么 \(pref_{i + 1, j} = pref_{i, j} + 1\)
    • 如果第 \(i\) 个数的第 \(j\) 个数码是 \(0\),那么 \(pref_{i + 1, j} = pref_{i, j}\)
  • 查询这个数的按位与/乃至按位或这种跟 \(1/0\) 个数很相关的,就可以利用预处理出来的前缀和 \(O(1)\) 查询。
  • 对于本题,显然前缀和等于数的间隔的位置的数码是 \(1\),把这些数码再用 \(1<<j\) 加入总和,最后判断是否符合答案。

代码实现

#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>

#define inf 0x7fffffff
#define endl '\n'

using namespace std;
using ll = long long;

void close_sync() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
}

const int N = 2e5 + 10;
const int bits = 30;
int pref[N][bits];
int a[N];
int n;

void bulidPrefix() {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < 30; j++) {
            if (a[i] & (1 << j)) {//1 << j 即产生一个只有第 j 位是 1 的二进制数,进而与 a[i] 比较判断该位是否为 1
                pref[i + 1][j] = pref[i][j] + 1;
            }
            else {
                pref[i + 1][j] = pref[i][j];
            }
        }
    }
}

void solve() {
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];
    bulidPrefix();
    int q; cin >> q;
    while (q--)
    {
        int l, k;
        cin >> l >> k;
        if (a[l - 1] < k) {cout << -1 << ' '; continue;}
        int low = l, high = n;
        int ans = l;
        while(low <= high) {
            int mid = low + (high - low >> 1);
            int num = 0;
            for (int j = 0; j < bits; j++) {
                if (pref[mid][j] - pref[l - 1][j] == mid - l + 1) {//说明这 mid - l + 1 个数的 j 位有 mid - l + 1 个 1,即该位答案为 1
                    num += 1 << j;
                }
            }
            if (num >= k) {
                low = mid + 1;
                ans = max(ans, mid);
            }
            else {
                high = mid - 1;
            }
        }
        cout << ans << ' ';
    }
    cout << endl;
}

int main() {
    close_sync();
    int _; std::cin >> _;
    while(_--) solve();
    return 0;
}

标签:CF1878E,前缀,int,pref,mid,按位,include,拆位
From: https://www.cnblogs.com/kdlyh/p/17980244

相关文章

  • js用前缀名查找class或id节点,js模糊查询某个dom节点
     1//参数dom为htmldom节点2//参数key为需模糊查询的名称字段3functionqueryClassNode(dom,key){4letcollectArray=[];5for(leti=0;i<dom.childNodes.length;i++){6//核心点7if(d......
  • 浅谈C++简单前缀和实现
    浅谈前缀和2023.9.28\(tips:\)文章持续更新中,欢迎关注\(upd:\)文章从洛谷博客迁移至博客园(\(2024.1.19\))洛谷B3612【深进1.例1】求区间和题目大E:有一个内部元素个数为\(n\)的数组\(a\),现在有m次询问,求a[l]到a[r]之间所有元素的和朴素的做法:#include<iostream>usin......
  • 刷题 位运算异或 异或前缀和
    2024.1.18杭州电子科技大学2023华为杯编程竞赛 解题思路首先可以知道,我们任意选一点为根root往下递归异或就可以得到f[i](root到i的路径异或值),那么 l到r的路劲异或值可以由f[l]^f[r]得出那么如何计算答案呢,就是用f[l]~f[r]分别异或f[x]......
  • 算法—前缀和
    1.一维前缀和S[i]=a[1]+a[2]+...a[i]//求s[n]a[l]+...+a[r]=S[r]-S[l-1]//求l-r的序列和2.二维前缀和S[i,j]=s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];第i行j列格子左上部分所有元素的和以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的和为:S[......
  • 前缀和求解(c++)
    数组ana1a2...an前缀和Si=a1+a2+...+ai①如何求②作用//一维数组前缀和的计算#include<iostream>usingnamespacestd;constintN=100010;inta[N],s[N];intn,m;intmain(){scanf("%d%d",&n,&m);for(inti=1;i<=n;......
  • 前缀和&差分
    前缀和&差分(蒟蒻篇)前缀和前缀和是指某序列的前n项和,而差分可以看成前缀和的逆运算。一般用于大量的求一段连续区间的和时间复杂度:预处理O(n),查询O(1)一维前缀和模板作用是:找a序列的一段连续区间的和for(inti=1;i<=n;i++)sum[i]=sum[i-1]+a[i];......
  • [刷题技巧] 前缀和相关知识点汇总
    一、前缀和的作用前缀和技巧适用于快速、频繁地计算一个索引区间内的元素之和。二、前缀和的思路将原始数组进行预处理,将来需要查询数据的时候,只需要查询预处理的前缀和数组的某些值即可。前缀和的求解是【动态规划】。三、前缀和的定义四、前缀和数组的构造//int[]nums......
  • 前缀和,二分 - [ABC203D] Pond
    AT_abc203_DPond题意给出一个\(N\timesN\)的矩阵,然后依次枚举\(k\timesk\)的子矩阵。对于\(k\timesk\)的子矩阵,一共有个\(k^2\)元素,找出其中的中位数。这里的中位数是子矩阵中元素从大到小排列的第$\left\lfloor\frac{k^2}{2}\right\rfloor$个元素。问......
  • Codeforces Round 918 (Div. 4) (前缀和,权值树状数组,二维偏序, python + golang)
    Dashboard-CodeforcesRound918(Div.4)-Codeforces  fromcollectionsimport*defsolve():a,b,c=list(map(int,input().split()))hs=defaultdict(int)hs[a]+=1hs[b]+=1hs[c]+=1foriinhs:ifhs[i]=......
  • Codeforces Round 918 (Div. 4)赛后总结(前缀和)(set部分用法)
    CodeforcesRound918(Div.4)赛后总结a,b题没啥好说的c题典中典没开longlong一回事,还有判断数a是否为完全平方数直接用sqrt(a)\(^2\)=a的判断就可以d题经典字符串问题首先,我们以一个字符数组的形式存数据。再根据已知cv,cvc两种形式,我们只需要判断c的时候看v是否有用过(可......