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

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