libreoj 10051「一本通 2.3 例 3」Nikitosh 和异或

博客探讨了如何求解一个长度为n的序列中,不相交的两个区间的异或和之和最大值的问题。通过前缀异或和与后缀异或和的概念,介绍了如何构建和使用平衡树数据结构来高效地找到最大异或和。文章还提供了代码实现的详细步骤。

博客观赏效果更佳

题意简述

给一个长度为 n n n 的序列 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an,求两个区间 [ l 1 , r 1 ] , [ l 2 , r 2 ] [l_1,r_1],[l_2,r_2] [l1,r1],[l2,r2],使得两端区间不相交,且两端区间的异或和加起来最大。

n ≤ 1 0 5 n\le 10^5 n105,每个 a i ≤ 1 0 9 a_i\le 10^9 ai109

思路

s i s_i si

你的代码采用的是暴力解法,时间复杂度为 $ O(n^2) $,对于 $ n = 10^5 $ 来说显然无法过。我们需要使用 **Trie(字典树)** 结构来优化异或最大值的问题。 ### 解题思路 要找出两个数使得它们的异或值最大,我们可以使用 **二进制 Trie 树**: 1. 将每个数从高位到低位插入 Trie。 2. 对于每个数,尝试在 Trie 中找出与它异或最大的另一个数: - 每一位尽量选择与当前位不同的路径走(即如果当前位是 0,就找 1;如果是 1,就找 0)。 3. 最终维护最大异或值。 ### 修改后的代码如下: ```cpp #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; const int BIT = 31; // 最大是32位整数 int n; long long a[N]; // Trie节点结构 struct TrieNode { TrieNode* children[2]; TrieNode() { children[0] = children[1] = nullptr; } }; void insert(TrieNode* root, long long num) { TrieNode* node = root; for (int i = BIT; i >= 0; i--) { int bit = (num >> i) & 1; if (!node->children[bit]) { node->children[bit] = new TrieNode(); } node = node->children[bit]; } } long long query(TrieNode* root, long long num) { TrieNode* node = root; long long xor_sum = 0; for (int i = BIT; i >= 0; i--) { int bit = (num >> i) & 1; int toggled_bit = 1 - bit; if (node->children[toggled_bit]) { xor_sum |= (1 << i); node = node->children[toggled_bit]; } else { node = node->children[bit]; } } return xor_sum; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n; for (int i = 0; i < n; i++) { cin >> a[i]; } TrieNode* root = new TrieNode(); long long max_xor = 0; for (int i = 0; i < n; i++) { insert(root, a[i]); long long res = query(root, a[i]); max_xor = max(max_xor, res); } cout << max_xor << endl; return 0; } ``` ### 说明 - 时间复杂度:$ O(n \cdot \text{BIT}) = O(n \cdot 32) \approx O(n) $,可以过 $ n = 10^5 $ 的数据。 - 空间复杂度:也控制在可接受范围内。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值