01字典树解决异或问题学习、

联系衔接:blcakcat

HDU 4825

从最高为开始贪心,如何可以走当前位的异或结果就走异或结果否则就走当前结果

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
LL value[32 * qq];
int ch[32 * qq][2];
int n, m, node_cnt;
void Init() {
	node_cnt = 1;
	mst(ch[0], 0);
}
void Insert(LL x) {
	int cur = 0;
	for(int i = 32; i >= 0; --i) {
		int idx = (x >> i) & 1;
		if(!ch[cur][idx]) {
			mst(ch[node_cnt], 0);
			ch[cur][idx] = node_cnt;
			value[node_cnt++] = 0;
		}
		cur = ch[cur][idx];
	}
	value[cur] = x;
}
LL Query(LL x) {
	int cur = 0;
	for(int i = 32; i >= 0; --i) {
		int idx = (x >> i) & 1;
		if(ch[cur][idx ^ 1])	cur = ch[cur][idx ^ 1];
		else	cur = ch[cur][idx];
	}
	return value[cur];
}

int main(){
	int t;	scanf("%d", &t);
	int Cas = 0;
	while(t--) {
		Init();
		scanf("%d%d", &n, &m);
		for(int i = 0; i < n; ++i) {
			LL x;	scanf("%lld", &x);
			Insert(x);
		}
		printf("Case #%d:\n", ++Cas);
		for(int i = 0; i < m; ++i) {
			LL x;	scanf("%lld", &x);
			printf("%lld\n", Query(x));
		}
	}
	return 0;
}


HDU 5536

题意:给出n个求,求出(si + sj) ^ sk 的最大值,i,j,k互不相等

思路:先对所有数建一颗01字典树,然后枚举i,j,将si与sj从字典序中删除,贪心找最大的结果

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 1e3 + 10;
const int INF = 1e9 + 10;
int ch[32 * qq][2], value[32 * qq], node_cnt, n;
LL num[qq];
void Init() {
	node_cnt = 1;
	mst(ch[0], 0);
	mst(value, 0);
}
void Insert(LL x) {
	int cur = 0;
	for(int i = 32; i >= 0; --i) {
		int idx = (x >> i) & 1;
		if(!ch[cur][idx]) {
			mst(ch[node_cnt], 0);
			ch[cur][idx] = node_cnt++;
		}
		cur = ch[cur][idx];
		value[cur]++;
	}
}
void Delete(LL x) {
	int cur = 0;
	for(int i = 32; i >= 0; --i) {
		int idx = (x >> i) & 1;
		cur = ch[cur][idx];
		value[cur]--;
	}
}
LL Query(LL x) {
	int cur = 0;
	LL ans = 0;
	for(int i = 32; i >= 0; --i) {
		int idx = (x >> i) & 1;
		if(ch[cur][idx ^ 1] && value[ch[cur][idx ^ 1]]) {
			ans |= (1LL << i);
			cur = ch[cur][idx ^ 1];
		} else {
			cur = ch[cur][idx];
		}
	}
	return ans;
}

int main(){
	int t;	scanf("%d", &t);
	while(t--) {
		Init();
		scanf("%d", &n);
		for(int i = 1; i <= n; ++i) {
			scanf("%lld", num + i);
			Insert(num[i]);
		}
		LL maxn = 0;
		for(int i = 1; i <= n; ++i) {
			Delete(num[i]);
			for(int j = i + 1; j <= n; ++j) {
				LL x = num[i] + num[j];
				Delete(num[j]);
				maxn = max(maxn, Query(x));	
				Insert(num[j]);
			}
			Insert(num[i]);
		}
		printf("%lld\n", maxn);
	}
	return 0;
}


HDU 3460

题意:有n个字符串,你有一个打印机,你要使用打印机输出所有字符串,打印机有三种操作,增加一个字符,删除一个字符,打印,问最少需要操作多少次

思路:很明显可以建一颗字典树,但关键在于怎么求解,可以这样思考首先我们知道打印每个字符串的贡献是n,那么现在我们还需要计算打印的贡献和删除的贡献,我们建了一颗字典树,那么字典树上的所有节点都是需要打印的,这就是所有打印的贡献,删除的贡献呢?我们要明确最后肯定只剩下一个字符串,所以之前的肯定会被删除掉,所以我们假设全部删除,再加上一个最长字符串即删除操作的贡献

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 1e4 + 10;
const int INF = 1e9 + 10;
int ch[qq * 26][26];
int node_cnt, n;
char st[qq];
void Init() {
	mst(ch[0], 0);
	node_cnt = 1;
}
void Insert() {
	int cur = 0;
	int len = strlen(st);
	for(int i = 0; i < len; ++i) {
		int idx = st[i] - 'a';
		if(!ch[cur][idx]) {
			mst(ch[node_cnt], 0);
			ch[cur][idx] = node_cnt++;;
		}
		cur = ch[cur][idx];
	}
}

int main(){
	while(scanf("%d", &n) != EOF) {
		Init();
		int maxn = 0;
		for(int i = 0; i < n; ++i) {
			scanf("%s", st);
			maxn = max(maxn, (int)strlen(st));
			Insert();
		}
		printf("%lld\n", -maxn + (node_cnt - 1) * 2LL + n);
	}
	return 0;
}


你可能感兴趣的:(算法學習)