【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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章