D2. Xor-Subsequence (hard version)
D2. Xor-Subsequence (hard version)
It is the hard version of the problem. The only difference is that in this version .
You are given an array of integers . Bryap wants to find the longest beautiful subsequence in the array.
An array , where , is a subsequence of length of the array .
Subsequence of length is called beautiful, if the following condition holds:
- For any () holds: .
Here denotes the bitwise XOR of and . For example, and .
Bryap is a simple person so he only wants to know the length of the longest such subsequence. Help Bryap and find the answer to his question.
Input
The first line contains a single integer () — the number of test cases. The description of the test cases follows.
The first line of each test case contains a single integer () — the length of the array.
The second line of each test case contains integers () — the elements of the array.
It is guaranteed that the sum of over all test cases does not exceed .
Output
For each test case print a single integer — the length of the longest beautiful subsequence.
Example
input
3
2
1 2
5
5 2 4 3 1
10
3 8 8 2 9 1 6 2 8 3
output
2
3
6
Note
In the first test case, we can pick the whole array as a beautiful subsequence because .
In the second test case, we can pick elements with indexes , and (in -indexation). For this elements holds: and .
解题思路
dp 的分析与 D1. Xor-Subsequence (easy version) 一样。观察式子 ,意味着 和 的二进制的前 个高位相同,第 个高位不同,且 的第 个高位是 , 的第 个高位是 。只考虑前 个高位,由于都相同因此有 ,从而有 。为此可以考虑在枚举完 后,把 插到 Trie 中。
为此就很容易想到对于 ,枚举 表示前 个高位相同而第 个高位不同,那么满足条件的 和 对应到 Trie 中就是从根节点开始走 步,与 路径相同的 。第 步取决于 的第 个高位,如果 的第 个高位是 则走 的分支,否则走 的分支。
为什么是这样子呢?列表格分类讨论就好了,讨论 的第 个高位的值(要满足 与 相同, 与 相同),比较 与 。
可以发现如果第 个高位不同,那么对于第 个高位必然有 ,所以应该走相反的分支。
另外 与 的第 个高位还要不同,因此可以维护一个 ,表示考虑所有的 中,关于 从根节点走 步到节点 ,且 的第 个高位是 的所有 的最大值。
剩余的细节请见代码。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5 + 10, M = N * 30;
int a[N];
int f[N];
int tr[M][2], g[M][2], idx;
void add(int x, int y) {
int t = x ^ y, p = 0;
for (int i = 29; i >= 0; i--) {
int u = t >> i & 1;
if (!tr[p][u]) tr[p][u] = ++idx;
p = tr[p][u];
g[p][y >> i & 1] = max(g[p][y >> i & 1], f[y]);
}
}
int query(int x, int y) {
int t = x ^ y, p = 0, ret = 1;
for (int i = 29; i >= 0; i--) {
int u = t >> i & 1;
if (tr[p][!u]) ret = max(ret, g[tr[p][!u]][~x >> i & 1] + 1);
p = tr[p][u];
if (!p) break;
}
return ret;
}
void solve() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", a + i);
}
idx = 0;
for (int i = 0; i < n * 30; i++) {
tr[i][0] = tr[i][1] = g[i][0] = g[i][1] = 0;
}
int ret = 0;
for (int i = 0; i < n; i++) {
f[i] = query(a[i], i);
add(a[i], i);
ret = max(ret, f[i]);
}
printf("%d\n", ret);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
Codeforces Round #815 (Div. 2) 讲解:https://www.bilibili.com/video/BV1mG4y1a7QS/
Codeforces Round #815 (Div. 2) Editorial:https://codeforces.com/blog/entry/106136
Codeforces Round #815 (Div. 2) D1 D2(字典树 + dp):https://zhuanlan.zhihu.com/p/555425330
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17865441.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效