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 ai109.

You are given an array of n integers a0,a1,a2,an1. Bryap wants to find the longest beautiful subsequence in the array.

An array b=[b0,b1,,bm1], where 0b0<b1<<bm1<n, is a subsequence of length m of the array a.

Subsequence b=[b0,b1,,bm1] of length m is called beautiful, if the following condition holds:

  • For any p (0p<m1) holds: abpbp+1<abp+1bp.

Here ab denotes the bitwise XOR of a and b. For example, 24=6 and 31=2.

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 t (1t105)  — the number of test cases. The description of the test cases follows.

The first line of each test case contains a single integer n (2n3105) — the length of the array.

The second line of each test case contains n integers a0,a1,...,an1 (0ai200) — the elements of the array.

It is guaranteed that the sum of n over all test cases does not exceed 3105.

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 11<20.

In the second test case, we can pick elements with indexes 1, 2 and 4 (in 0-indexation). For this elements holds: 22<41 and 44<12.

 

解题思路

  dp 的分析与 D1. Xor-Subsequence (easy version) 一样。观察式子 aji<aij,意味着 ajiaij 的二进制的前 k1 个高位相同,第 k 个高位不同,且 aji 的第 k 个高位是 0aij 的第 k 个高位是 1。只考虑前 k1 个高位,由于都相同因此有 aji=aij,从而有 aii=ajj。为此可以考虑在枚举完 ai 后,把 aii 插到 Trie 中。

  为此就很容易想到对于 ai,枚举 k 表示前 k1 个高位相同而第 k 个高位不同,那么满足条件的 ajj 对应到 Trie 中就是从根节点开始走 k1 步,与 aii 路径相同的 ajj。第 k 步取决于 aii 的第 k 个高位,如果 aii 的第 k 个高位是 0 则走 1 的分支,否则走 0 的分支。

  为什么是这样子呢?列表格分类讨论就好了,讨论 ai,i,aj,j 的第 k 个高位的值(要满足 aji 相同,aij 相同),比较 aiiajj

aj i ai j aii ajj
0 0 0 1 0 1
0 0 1 0 1 0
1 1 0 1 1 0
1 1 1 0 0 1

  可以发现如果第 k 个高位不同,那么对于第 k 个高位必然有 aiiajj,所以应该走相反的分支。

  另外 aij 的第 k 个高位还要不同,因此可以维护一个 g(u,0/1),表示考虑所有的 aj,j[0,i1] 中,关于 ajj 从根节点走 k 步到节点 u,且 j 的第 k 个高位是 0/1 的所有 f(j) 的最大值。

  剩余的细节请见代码。

  AC 代码如下,时间复杂度为 O(nlogA)

#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

posted @   onlyblues  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示