D2. 388535 (Hard Version)

题目:D2. 388535 (Hard Version)

大佬题解

考点:01字典树

题意:给定一个长度为 r − l + 1 r - l + 1 rl+1 的数组,求 x x x 的值,使得数组中 a i ⨁ x a_i \bigoplus x aix 后的值在区间 [ l , r ] [l,r] [l,r] 中。

a ⨁ b = c ⟺ b ⨁ c = a a \bigoplus b = c \Longleftrightarrow b \bigoplus c = a ab=cbc=a

1 ⨁ 1 = 0 , 1 ⨁ 0 = 1 1 \bigoplus 1 = 0,1 \bigoplus 0 = 1 11=010=1

a ≠ b ⟺ a ⨁ x ≠ x ⨁ b a \not= b \Longleftrightarrow a \bigoplus x \not= x \bigoplus b a=bax=xb

思路:区间 [ l , r ] [l,r] [l,r] 中的任意两个值都不相同,所以数组中 a i ≠ a j ( i ≠ j ) a_i \not= a_j(i \not= j) ai=aj(i=j)。又因为 ( L ⨁ x ) ⨁ L = x (L \bigoplus x) \bigoplus L = x (Lx)L=x ,只需遍历 a i a_i ai 求出符合条件的 a i ⨁ L a_i\bigoplus L aiL ,即为答案。

如果每求出一个 x x x 的值,便遍历一遍数组 a i a_i ai 查看当前 x x x 是否符合条件,这样会导致 T L E TLE TLE。此处,只需求出 x x x a i a_i ai 异或的最大值和最小值是否等于 r r r l l l ,便可确定 x x x 是否符合要求。当前确定 a i ⨁ x a_i \bigoplus x aix 的值都不相同,而且最大值与最小值为 r r r l l l ,所以整个数组异或后的值都在区间 [ l , r ] [l,r] [l,r] 中。

多组测试数据初始化 01 01 01字典树

//在插入值时初始化
void add(int k) {
	int p = 0;
	for(int i=20;i>=0;i--) {
		int L = (k >> i) & 1;
		if(tr[p][L] == 0) {
			tr[tot][0] = tr[tot][1] = 0;
			tr[p][L] = tot ++;
		}
		p = tr[p][L];
	}
	end[p] = k;
}

tot = 1;
tr[0][0] = tr[0][1] = 0;

01 01 01字典树求异或最大值

int q_mx(int k) {
	int p = 0;
	for(int i=20;i>=0;i--) {
		int L = (k >> i) & 1;
		if(tr[p][L ^ 1] != 0) p = tr[p][L ^ 1];
		else p = tr[p][L];
	}
	return end[p] ^ k;
}

01 01 01字典树求异或最小值

int q_mi(int k) { 
	int p = 0;
	for(int i=20;i>=0;i--) {
		int L = (k >> i) & 1;
		if(tr[p][L] != 0) {
			p = tr[p][L];
		}
		else {
			p = tr[p][L ^ 1];
		}
	}
	return end[p] ^ k;
}

总代码

#include
#include

using namespace std;
const int N = 5e5 + 10;
int tr[N * 27][2],a[N],tot,end[N];

void add(int k) {
	int p = 0;
	for(int i=20;i>=0;i--) {
		int L = (k >> i) & 1;
		if(tr[p][L] == 0) {
			tr[tot][0] = tr[tot][1] = 0;
			tr[p][L] = tot ++;
		}
		p = tr[p][L];
	}
	end[p] = k;
}

int q_mi(int k) { 
	int p = 0;
	for(int i=20;i>=0;i--) {
		int L = (k >> i) & 1;
		if(tr[p][L] != 0) {
			p = tr[p][L];
		}
		else {
			p = tr[p][L ^ 1];
		}
	}
	return end[p] ^ k;
}

int q_mx(int k) {
	int p = 0;
	for(int i=20;i>=0;i--) {
		int L = (k >> i) & 1;
		if(tr[p][L ^ 1] != 0) p = tr[p][L ^ 1];
		else p = tr[p][L];
	}
	return end[p] ^ k;
}

int main() {
	int t;
	scanf("%d",&t);
	while(t --) {
		tot = 1;
		tr[0][0] = tr[0][1] = 0;
		int l,r;
		scanf("%d %d",&l,&r);
		int n = r - l + 1;
		for(int i=0;i

你可能感兴趣的:(Cross,Fire,c++,算法)