Codeforces Round 956 F. array-value 【01Trie查询异或最小值】

ops/2024/10/20 18:58:55/

F

题意

给定一个非负整数数组 a a a
对每个长度至少为 2 2 2 的子数组,定义其权值为:子数组内两两异或值最小
b ⊂ a [ l , r ] , w ( b ) = min ⁡ l ≤ i < j ≤ r { a i ⨁ a j } b \subset a[l, r], \quad w(b) = \min_{l \leq i < j \leq r} \{a_i \bigoplus a_j\} ba[l,r],w(b)=minli<jr{aiaj}

求出所有子数组中权值第 k k k 小的权值

思路

我们可以先二分答案 m i d mid mid,并且快速统计有多少个子数组的权值 ≤ m i d \leq mid mid,记为 c n t cnt cnt,如果 c n t ≥ k cnt \geq k cntk,说明答案可能比 m i d mid mid 更小,否则说明答案一定比 m i d mid mid 更大

问题在于如何快速统计 c n t cnt cnt? 注意到其实随着子数组越大(越长),那么其权值一定是非递增的,也就是说更大的子数组会有更大的可能性满足权值 w ≤ m i d w \leq mid wmid

基于上述的观察,我们考虑先枚举区间的右端点 r p rp rp,我们要选择最大 l p lp lp,使得 a [ l p , r p ] a[lp, rp] a[lp,rp] 里, 任意一个右端点在 r p rp rp 的子数组,其权值都大于 m i d mid mid,也即是 a [ l p , r p ] a[lp, rp] a[lp,rp] 里任意两两的异或权值都大于 m i d mid mid,等价于两两异或的最小值大于 m i d mid mid

又由于我们是从小到大枚举 r p rp rp 的,那么上一轮的 r p − 1 rp - 1 rp1 就对应着其极大的 l p lp lp,如果 l p lp lp 再小(即子数组更长),那么就会破坏上面的约束,使得最小值小于等于 m i d mid mid

因此新加入 a r p a_{rp} arp 时,我们只需要在 01 T r i e 01 \; Trie 01Trie 上对 a r p a_{rp} arp 查询异或最小值(因为前面 [ l p , r p − 1 ] [lp, rp - 1] [lp,rp1] 两两异或值都符合要求),不难发现,我们的 l p lp lp非递减的,这是一个双指针的过程。

对于一对极大的 [ l p , r p ] [lp, rp] [lp,rp],右端点在 r p rp rp 的权值小于等于 m i d mid mid 的子数组数量为 l p − 1 lp - 1 lp1,即左端点的选择范围是: [ 1 , l p − 1 ] [1, lp - 1] [1,lp1]

l p lp lp 右移时(删除某些 a l p a_{lp} alp),我们只需要在 01 T r i e 01 \; Trie 01Trie擦除这些值即可

这样子就在 O ( n log ⁡ A ) O(n \log A) O(nlogA) 下快速统计出了权值小于等于 m i d mid mid 的子数组数量

总体时间复杂度: O ( n log ⁡ 2 A ) O(n \log ^ 2 A) O(nlog2A)

注意每次二分都要清空 T r i e Trie Trie

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
#define ALL(v) v.begin(), v.end()
#define Debug(x, ed) std::cerr << #x << " = " << x << ed;const int INF=0x3f3f3f3f;
const long long INFLL=1e18;typedef long long ll;const int N = 100005;struct node{int son[2];int cnt;int idx;
}tree[N * 32];int tot;void clear(){fore(i, 0, tot + 1){tree[i].cnt = tree[i].idx = tree[i].son[0] = tree[i].son[1] = 0;}tot = 0;
}void insert(int x, int i){int now = 0;for(int i = 29; i >= 0; --i){int ch = (x >> i & 1);if(!tree[now].son[ch])tree[now].son[ch] = ++tot;now = tree[now].son[ch];++tree[now].cnt;}tree[now].idx = i;
}std::pair<int, int> query(int x){ //return [mn, idx]int res = 0;int now = 0;for(int i = 29; i >= 0; --i){int ch = (x >> i & 1);int to = tree[now].son[ch];if(to && tree[to].cnt){now = to;}else{res |= (1 << i);now = tree[now].son[ch ^ 1];}}return {res, tree[now].idx}; //返回异或最小值和产生的下标i
}void erase(int x){int now = 0;for(int i = 29; i >= 0; --i){int ch = (x >> i & 1);now = tree[now].son[ch];--tree[now].cnt;}
}int main(){std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);int t;std::cin >> t;while(t--){int n;ll k;std::cin >> n >> k;std::vector<int> a(n + 1);fore(i, 1, n + 1) std::cin >> a[i];ll ans = 0;ll l = 0, r = 2e9;while(l <= r){clear();ll mid = l + r >> 1;int lp = 1, rp = 2;ll cnt = 1ll * n * (n - 1) / 2;;insert(a[1], 1);while(rp <= n){while(true){if(lp == rp) break;auto [mn, i] = query(a[rp]);if(mn > mid) break;while(lp <= i){erase(a[lp]);++lp;}}if(lp < rp){cnt -= rp - lp; //减去权值大于mid的子数组数量}insert(a[rp], rp);++rp;}if(cnt >= k){ans = mid;r = mid - 1;}else l = mid + 1;}std::cout << ans << endl;clear();}return 0;
}

http://www.ppmy.cn/ops/56251.html

相关文章

k8s常用组件之pod

简介 Pod 是 Kubernetes 中最小的部署单元,也是 Kubernetes 集群中的基本工作单元。一个 Pod 通常包含一个或多个密切相关的容器。 Pod 的主要特点包括: 容器组合 Pod 可以包含一个或多个密切相关的容器,这些容器共享网络、存储等资源。这些容器通常被称为 Pod 内的"同…

ABAP 一篇作业分享

目录 一&#xff1a;要件定义&#xff1a; 二&#xff0c;具体代码&#xff1a; 三&#xff0c;测试结果&#xff1a; 一&#xff1a;要件定义&#xff1a; 二&#xff0c;具体代码&#xff1a; *&-------------------------------------------------------------------…

用MATLAB绘制三向应力圆

% 定义主应力值 sigma1 100; % MPa sigma2 50; % MPa sigma3 -33; % MPa sigma_m1(sigma1 sigma3)/2; sigma_m2(sigma1 sigma2)/2; sigma_m3(sigma2 sigma3)/2; % 计算半径 r1 (sigma1 - sigma3) / 2; r2 (sigma1 - sigma2) / 2; r3 (sigma2 - sigma3…

Windows Server 2012 R2查看IIS版本

文章目录 一、方法一1.win R 键打开运行窗口 → 输入 "regedit" → 点击【确定】2.HKEY_LOCAL_MACHINE → SOFTWARE → Microsoft → InetStp 二、方法二1.win R 键打开运行窗口 → 输入 "inetmgr" → 点击【确定】2.点击 【帮助】 → 选择【关于 Intern…

模型泛化与工程技巧-模型泛化

1. 模型存在问题 1.1 过拟合 过拟合(Overfitting):模型过于紧密或精确地匹配特定数据集,以致于无法良好地拟合其他数据或预测未来的观察结果的现象。通俗的来讲,就是训练的模型在训练集上的精确度很高,但是在测试集上的精确度却很差的现象。 1.2 如何防止过拟合—数据角度 …

快速测试electron环境是否安装成功

快速测试electron环境是否安装成功 测试代码正确运行的效果运行错误的效果v22.4.1 版本无法使用v20.15.1版本无法使用v18.20.4 版本无法使用 测试代码 1.npx create-electron-app my-electron-app 2.cd my-electron-app 3.npm start 正确运行的效果 环境没问题,你就会正常运…

持久化存储与设备环境查询的最佳实践

ArkUI框架中的PersistentStorage和Environment 在ArkUI框架中&#xff0c;持久化存储和设备环境查询是应用开发中不可或缺的两个重要功能。在本文中&#xff0c;我们将深入了解框架提供的PersistentStorage和Environment&#xff0c;它们的用途、限制条件以及在应用开发中的使…

windows下使用编译opencv在qt中使用

记录一下&#xff1a;在windows下qt使用opencv 1、涉及需要下载的软件 CMake 下载地址opecnv下载地址mingw(需要配置环境变量) 这个在下载qt的时候可以直接安装一般在qt的安装路径下的tool里比如我的安装路径 (C:\zz\ProgramFiles\QT5.12\Tools\mingw730_64) 2、在安装好CMake…