[trie]【LOJ10050】「一本通 2.3 例 2」The XOR Largest Pair

题目分析

详细讲解可参考《一本通.提高篇》p86内容。简单讲就是可以将所有的数字转化成二进制数,因此相当于长度为32的数字字符串,且数字为0和1。对于N个数,我们可以依次把这些数x,插入到trie中,然后我们找出trie中已经存在的某个数(二进制),这个数能与x异或最大。那么怎么才能找到这个最大的数呢?我们类似于trie查找,不过要“异或”查找,就是尽量选择不同的,没有节点才选相同的。这样操作完32个节点,一定能找到异或结果最大的数。然后将这个数与x以后得到一个数ans,依次更新ans的值,就能得到结果了。时间复杂度很显然是32*N.

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3.2e6+10;
int ch[maxn][2];  // 转成二进制 
char s[32];
int cnt = 1;  // root

void insert(char *s){
	int len = 32;
	int u = 1;
	for(int i=0; i<len; i++){
		int t = s[i]-'0';
		if(!ch[u][t])
			ch[u][t] = ++ cnt;
		u = ch[u][t];
	}
}

int find(char *s){ // 尽可能反着走, 找出这个做异或的数 
	int len = 32;
	int u = 1;
	int x = 1;
	for(int i=0; i<len; i++){
		int t = s[i]-'0';
		int tmp = t^1;
		if(ch[u][tmp]){
			x = x*2+tmp;
			u = ch[u][tmp];
		}else{
			x = x*2+t;
			u = ch[u][t];
		}
	}
	return x;
}

void change(int x){ // 转为二进制
	if(x>=0)  // 符号 
		s[0] = '0';
	else{ 
		s[0] = '1';
		x = -x; 
	} 
	int k = 31;  // 最后一位 
	while(x){
		s[k--] = x%2+'0';
		x /= 2;
	}
	while(k>=1){ // 前面补0 
		s[k--] = '0';
	}
}

int main(){
	int n, x, ans = -1;
	scanf("%d", &n);
	for(int i=1; i<=n; i++){
		scanf("%d", &x);
		change(x);
		insert(s);
		int t = x^find(s);
		ans = max(t, ans);
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2020-06-02 18:04  gdgzliu  阅读(233)  评论(0编辑  收藏  举报