【CF1625D】Binary Spiders(Trie)
题目链接
2种方法
结论版
一个很显然的结论就是\(n\)个数里两两之间最小异或和一定是相邻的\(2\)个数
于是就有了以下\(DP\),
先将原数列排序
令\(f[i]\)表示最大的数为\(a_i\)的情况下最多能选几个数
显然有以下转移
\[f[i]=\max_{a_j \text{ xor } a_i \geq k} {f[j]} + 1
\]
于是可以用字典树存当前节点包含的最大\(f\)值
查询的时候顺着\(a_i\text{ xor } k\)走,看情况对不走的点取最大值就行。
记录方案也是个很头疼的事呢
无结论版
依然是\(Trie\)啦。
先把所有数插到\(Trie\)里
先跳到和\(k\)最高位所在的一层\(p\)。
显然这一层节点的子树相互独立,因为两个不同子树的数异或后前几位肯定不为\(0\),而\(k\)前几位为\(0\)
对于一个节点,最多只能选2个,因为如果选三个那么肯定有\(2\)个的数的\(p\)层一样,那样异或后就一定小于\(k\)了。
所以对于\(p\)层的每个节点,只需要考虑能否在左右子树各找一个数使异或和\(\geq k\)
考虑 \(\text{check(int x, int y, int d)}\) 表示要从 \(x,y\)(深度 \(d\))子树中各找一个数,使得异或和 \(\geq k\)。(返回值为一个 \(pair\) 表示两个数在数组中的下标)
如果 \(k\) 这一位是 \(0\) 且当前位异或和可以凑出 \(1\),则直接返回当前位凑出 \(1\) 的任意两个数就好了。
否则看当前位异或和是否能和 \(k\) 一样,不能的话返回无解
结论版代码
#include <bits/stdc++.h>
#define rep(i, m, n) for(int i = (m); i <= (n); ++i)
#define dop(i, m, n) for(int i = (m); i >= (n); --i)
//#define submit
using namespace std;
const int N = 300010;
int n, m, cnt = 1, pre[N];
struct node{
int id, val;
int operator < (const node A) const{
return val < A.val;
}
}a[N];
struct Trie{
int ch[2], val, pos;
Trie(){
ch[0] = ch[1] = val = pos = 0;
}
int operator < (const Trie A) const{
return val != A.val ? val < A.val : pos < A.pos;
}
}t[N * 31], tmp;
Trie get(int x){
int u = 1;
Trie ans;
dop(i, 30, 0){
int p = (x >> i & 1) ^ (m >> i & 1);
if(!t[u].ch[p])
if(m >> i & 1)
return ans;
else return max(ans, t[t[u].ch[!p]]);
if(!(m >> i & 1)) chkmax(ans, t[t[u].ch[p^1]]);
u = t[u].ch[p];
}
return max(ans, t[u]);
}
void insert(int x, int y, int z){
int u = 1;
dop(i, 30, 0){
int p = x >> i & 1;
if(!t[u].ch[p]) t[u].ch[p] = ++cnt;
u = t[u].ch[p];
if(y > t[u].val || y == t[u].val && z > t[u].pos){
t[u].val = y, t[u].pos = z;
}
}
}
int ans, pos;
void print(int x){
if(pre[x]) print(pre[x]);
printf("%d ", a[x].id);
}
int main(){
scanf("%d%d", &n, &m);
rep(i, 1, n) scanf("%d", &a[i].val), a[i].id = i;
sort(a+1, a+n+1);
rep(i, 1, n){
tmp = get(a[i].val);
pre[i] = tmp.pos;
if(tmp.pos) tmp.val += tmp.val ? 1 : 2;
if(tmp.val > ans){
ans = tmp.val;
pos = i;
}
insert(a[i].val, tmp.val, i);
}
printf("%d\n", ans ? ans : -1);
if(ans) print(pos);
return 0;
}