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

Problem - 1878E - Codeforces

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

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

1|0拆位思想

比如要计算

1110001 1101110 0100010

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

0100000

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

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

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

推广到 nm 位的二进制数:

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

2|0代码实现

#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; }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/17980244.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示