8 ABC425 G 题解

news/2025/10/10 21:12:40/文章来源:https://www.cnblogs.com/michaele/p/19133894

ABC425 G

题面

给定两个正整数 \(N,M\) 以及一个长度为 \(N\) 的非负整数序列 \(A = A_1, A_2, ..., A_N\)。求

\[\sum_{x = 0}^{M - 1} \min_{1 \le i \le N} (x \oplus A_i) \]

\(1 \le N \le 2 \times 10^5\)

\(1 \le M \le 10^9\)

\(0 \le A_i \le 10^9\)

题解

首先,如果 \(M \le 10^5\),那么是不是可以想到把 \(A\) 建成一棵 01trie,然后依次在 tire 上查询每个 \(x\)

我们设 \(d\) 表示最多有多少层,也就是 \(\log V\),其中 \(V\) 是值域,那么时间复杂度就是 \(O(Md)\)

那么我们可以先建出一棵 trie,然后考虑如何处理 \(M \le 10^9\) 情况。

思考我们在 trie 上找异或最小值或者异或最大值,一般都是从上往下贪心的去遍历 trie,对于一个数是这样,对于一段连续的数,也是一样的,我们只关注最高位的情况。

所以我们可以将 \(0 \sim val\) 这一个区间的询问当成一个询问,然后对这个询问的情况进行分类讨论。

我们设当前询问为 \(0 \sim val\),保证到第 \(k\) 层时 \(0 \sim val\) 二进制最高位的 \(1\) 处在第 \(k\) 位及以下,分两种情况来讨论:

  • \(val < 2^k\):也就说明 \(0 \sim val\) 中的所有数的第 \(k\) 位都是 \(0\),尽量走左子树,如果走右子树,答案要加上 \(2^k \times (val + 1)\)

  • \(val \ge 2^k\):这时要分成两段分别处理:

    \(0 \sim 2^k - 1\):和上面的情况一样,尽量走左子树,否则答案加 \(2^k \times 2^k\)

    \(2^k \sim val\):这一段的第 \(k\) 位都是 \(1\),所以应该尽量走右子树,否则答案加 \((val + 1) \times 2^k\)。这一段走到下一层的时候应该减去 \(2^k\),因为要保证每次到下一层时二进制最高位的 \(1\) 处在第 \(k - 1\) 位及以下。

我们这样去处理的话,时间复杂度最坏还是 \(O(Md)\) 的,因为如果每层都分成两段,那么每到一层,询问个数都会翻倍,后面就会有 \(10^9\) 个询问,这是不能接受的。

要解决这个问题,就要用到一个神奇的 trick。

假如有两个询问,都是 \(0 \sim val\),那么我们将两个询问合并,再记录一个 \(cnt\) 表示 \(0 \sim val\) 的询问出现了多少次。这样就能将时间复杂度降到 \(O(\frac d 2 \times 2^{d/2} \log V)\)

考虑证明,我们将 dfs 的层分成上 15 层和下 15 层:

对于上 15 层,我们最多分出 \(2^{15}\) 个询问。

对于下 15 层,因为值域为 \(2^{15}\),所以经过合并,最多也只有 \(2^{15}\) 个询问。

所以在每一层的询问个数都不会超过 \(2^{15}\) 个。

那么最后的时间复杂度就是 \(O(\frac d 2 \times 2^{d/2} \log V)\),其中 \(\frac d 2\) 表示每层将 \(2^{d / 2}\) 个询问进行合并,排序的时间复杂度。(经过yyb大佬指点,这个排序的时间复杂度是可以通过实现消去的。因为只有拆分会影响顺序,通过维护两个队列,一个是拆分的,一个是未拆分的,这样两个队列都是有序的,合并的时候就能实现线性合并了)

关于实现细节,因为每个询问都是从 \(0\) 开始的,所以我们只记录右端点即可,在每个节点的询问可以用一个 vector 来储存。

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>using namespace std;const int N = 2e5 + 10, M = N * 30;typedef long long ll;
typedef pair <int, int> pii;int n, m;
int a[N], t[M][2], idx;
ll ans = 0;void insert (int x) {int p = 0;for (int i = 30; i >= 0; i --) {int ch = (x >> i) & 1;if (!t[p][ch]) t[p][ch] = ++ idx;p = t[p][ch];}
}void dfs (vector <pii> Q, int p, int k) {if (k < 0) return;vector <pii> ql, qr;sort (Q.begin (), Q.end ());for (int i = 0; i < (int)Q.size (); i ++) {while (i + 1 < (int)Q.size () && Q[i].first == Q[i + 1].first) {Q[i + 1].second += Q[i].second;i ++;}int val = Q[i].first, cnt = Q[i].second;if (val < (1 << k)) {if (t[p][0]) ql.emplace_back (val, cnt);else {ans += 1ll * (val + 1) * (1 << k) * cnt;qr.emplace_back (val, cnt);}} else {if (t[p][0]) ql.emplace_back ((1 << k) - 1, cnt);else {ans += 1ll * (1 << k) * (1 << k) * cnt;qr.emplace_back ((1 << k) - 1, cnt);}if (t[p][1]) qr.emplace_back (val - (1 << k), cnt);else {ans += 1ll * (val - (1 << k) + 1) * (1 << k) * cnt;ql.emplace_back (val - (1 << k), cnt);}}}if (t[p][0] && ql.size ()) dfs (ql, t[p][0], k - 1);if (t[p][1] && qr.size ()) dfs (qr, t[p][1], k - 1);
}int main () {cin >> n >> m;for (int i = 1; i <= n; i ++) {cin >> a[i];insert (a[i]);}vector <pii> Q;Q.emplace_back (m - 1, 1);dfs (Q, 0, 30);cout << ans << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/934409.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能防御,安全赋能:AI-FOCUS 滤海AI DLP 化解外部 AI 风险

在“员工把数据投喂给第三方AI”的常见场景下,企业需要一款可在输入与上传瞬时介入的产品。AI-FOCUS 滤海AI DLP 以流式网关为核心,在用户向大模型输入文本与提交文件/图片时进行敏感数据识别,按风险等级执行放行、…

VS code 中代码补全 自动补全函数括号

使用vscode的pylance插件补全python代码的时候无法补全函数的括号 需要在settings.json中添加这一行即可

学习ReAct并使用langgraph实现一个简单的ReAct AI Agent!!

ReAct介绍 要介绍ReAct最好要知道它是从哪来的。 ReAct这个概念出自《REACT : SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS》这篇很牛的论文。 论文地址:https://arxiv.org/abs/2210.03629 我们先来看下这篇…

23种设计模式之【策略模式】-核心原理与 Java 实践 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

abc 408 d~f

这次做了一次 abc,d 做出来了,但是比较麻烦,又用正确方法写了一遍,整理一下 d,e,f,g 有一些超纲。 abc408d 考虑把区间 \(l,r\) 最后变成 1,然后尝试去表示这个时候的答案。 \(sum[i]\) 表示 \(i\) 位置以及之前…

RMQ与LCA学习笔记

在开始之前先提一下RMQ与LCA这两个东西有什么关系 对于一个序列,对它构建出一颗笛卡尔树之后,两个点的LCA就是原序列中这两个点之间的最大值/最小值(取决于建树时的比较方式) 而对于一棵树,求出来他的欧拉序之后,…

the charm of Chinese language

The charm of Chinese language is you use it to read books. when I can read the original books translation as Chinese. I found the original one lets people dizzy, maybe it needs some graphs to make the …

mamba-硬件感知算法

扫描操作由于A B C这些矩阵现在是动态的了,因此无法使用卷积表示来计算它们(卷积核是固定的),因此,我们只能使用循环表示,如此也就而失去了卷积提供的并行训练能力 Mamba通过并行扫描(parallel scan)算法使得最终并…

完整教程:lua代码解析1

完整教程:lua代码解析1pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &qu…

system表空间丢失部分文件恢复---惜分飞

system表空间丢失部分文件恢复---惜分飞联系:手机/微信(+86 17813235971) QQ(107644445) 标题:system表空间丢失部分文件恢复 作者:惜分飞©版权所有[未经本人同意,不得以任何形式转载,否则有进一步追究法律责任…

二维数点

介绍 给出一个二维平面內的若干个点,多次询问某个矩形区域內包含多少个点(边界也算)。又或者,给一个长为 n nn 的序列,多次询问区间 [ l , r ] [l,r][l,r] 中值在 [ x , y ] [x,y][x,y] 内的元素个数。 例题 P190…

gitee和github如何修改仓库名并且保持与原远程仓库的连接?(手把手教学) - 实践

gitee和github如何修改仓库名并且保持与原远程仓库的连接?(手把手教学) - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font…

2025.10.10总结 - A

今天上了节英语,感觉还可以,下雨了,一直在宿舍,感觉很爽。

[20251010]建立完善tpt的prr.sql脚本.txt

[20251010]建立完善tpt的prr.sql脚本.txt--//昨天在测试时不小心输入pr命令时多输入一个r,没想到居然执行了,说明在本目录或者SQLPATH环境目录下存在prr.sql脚本。--//当时忙着处理其他事情,先把这件事情放一放,今…

第十一篇

今天是10月10号,今天只上了一节英语课,学习了新的单词,颇有收获。

[Flutter] Flutter APK构建签名并推广到Github workflow

[Flutter] Flutter APK构建签名并推广到Github workflowFlutter APK构建签名并推广到Github workflow 最近在开发flutter软件的时候发现构建出来的apk在手机上不能直接覆盖更新,会提示签名不一致,但由于我的软件是在…

Windows 电脑安装 XTerminal 1.25.1 x64 版(带安装包下载关键词)​

Windows 电脑安装 XTerminal 1.25.1 x64 版(带安装包下载关键词)​​XTerminal​ 是一款运行在 Windows 系统上的终端工具(类似命令行窗口),通常用于开发者、运维人员或高级用户来执行命令、连接远程服务器、运行…

YOLOv11的神经辐射场(NeRF)辅助训练-(通过合成视角增强内容多样性)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

题解:AT_arc138_f [ARC138F] KD Tree

题意:平面上有 \(n\) 个点 \((i,p_i)\),\(p\) 是一个排列。每次操作可以选择 \(x/y\) 和一个坐标,将点列分成左右/上下两边(保持两边的相对顺序不变),分别递归下去,直到只剩下一个点,把它加入答案序列末尾。求…