D2. Xor-Subsequence (hard version)

发布时间 2023-11-29 17:43:26作者: onlyblues

D2. Xor-Subsequence (hard version)

It is the hard version of the problem. The only difference is that in this version $a_i \le 10^9$.

You are given an array of $n$ integers $a_0, a_1, a_2, \ldots a_{n - 1}$. Bryap wants to find the longest beautiful subsequence in the array.

An array $b = [b_0, b_1, \ldots, b_{m-1}]$, where $0 \le b_0 < b_1 < \ldots < b_{m - 1} < n$, is a subsequence of length $m$ of the array $a$.

Subsequence $b = [b_0, b_1, \ldots, b_{m-1}]$ of length $m$ is called beautiful, if the following condition holds:

  • For any $p$ ($0 \le p < m - 1$) holds: $a_{b_p} \oplus b_{p+1} < a_{b_{p+1}} \oplus b_p$.

Here $a \oplus b$ denotes the bitwise XOR of $a$ and $b$. For example, $2 \oplus 4 = 6$ and $3 \oplus 1=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$ ($1 \leq t \leq 10^5$)  — the number of test cases. The description of the test cases follows.

The first line of each test case contains a single integer $n$ ($2 \leq n \leq 3 \cdot 10^5$) — the length of the array.

The second line of each test case contains $n$ integers $a_0,a_1,...,a_{n-1}$ ($0 \leq a_i \leq 200$) — the elements of the array.

It is guaranteed that the sum of $n$ over all test cases does not exceed $3 \cdot 10^5$.

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 $1 \oplus 1 < 2 \oplus 0$.

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

 

解题思路

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

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

  为什么是这样子呢?列表格分类讨论就好了,讨论 $a_i, i, a_j, j$ 的第 $k$ 个高位的值(要满足 $a_j$ 与 $i$ 相同,$a_i$ 与 $j$ 相同),比较 $a_i \oplus i$ 与 $a_j \oplus j$。

$a_j$ $i$ $a_i$ $j$ $a_i \oplus i$ $a_j \oplus j$
$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$ 个高位必然有 $a_i \oplus i \ne a_j \oplus j$,所以应该走相反的分支。

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

  剩余的细节请见代码。

  AC 代码如下,时间复杂度为 $O(n \log{A})$:

#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