HDU-5536-Chip Factory(01Trie)

题目地址

HDU-5536-Chip Factory

题意

共有 T T T组数据,每组数据都给定一个长度为 n n n的整数序列,然后从里面选出来三个数 a i , a j , a k a_i,a_j,a_k ai,aj,ak,要求 ( a i + a j ) ⊕ a k (a_i+a_j)\oplus a_k (ai+aj)ak的值最大。

数据范围

3 ≤ n ≤ 1000 3 \le n \le 1000 3n1000
1 ≤ T ≤ 1000 1 \le T \le 1000 1T1000
0 ≤ a i ≤ 1 0 9 0 \le a_i \le 10^9 0ai109

思路

Trie树有一道经典例题,是一个整数序列,然后选择两个数令其异或和最大。先回顾一下那道题的思路:我们将所有的数字全部插入Trie树中,然后我们循环遍历所有的数字,求出最大异或和。
这道题在例题的基础上增加了一些难度,题目要求从数列1中选出两个数相加后与第三个数异或,求所选数字组成的最大值。

如果这道题用暴力来写的话,时间复杂度就是 O ( n 3 ) O(n^3) O(n3) 妥妥超时,但是只需降低一个时间复杂度,令时间复杂度降为 O ( n 2 l o g n ) O(n^2logn) O(n2logn)就不会超时了。因此我们考虑优化暴力的思路。

由于需要选出来两个数字相加,所以我们需要用两层循环枚举两个相加的数字,然后在枚举第三个数字时,我们可以利用上面例题的思路,使用01Trie进行求解。在暴力枚举完两个相加的数字之后,剩下的操作就和上面的例题一模一样。

例题地址

AcWing 143. 最大异或对

实现代码(c++)

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
#define LL long long 
#define ULL unsigned long long 
#define PII pair<int, int>
#define lowbit(x) (x & -x)
#define Mid ((l + r) >> 1)
#define ALL(x) x.begin(), x.end()
#define endl '\n'
#define fi first 
#define se second

const int INF = 0x7fffffff;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;

int n, a[N], res;
//val数组记录异或和,s数组记录该节点出现的次数
int t[N][2], s[N], val[N], cnt;

void Insert(int x) {
	int p = 0;
	for(int i = 30; i >= 0; i -- ) {
		int &u = t[p][x >> i & 1];
		if(!u) {
			u = ++ cnt;
			memset(t[cnt], 0, sizeof t[cnt]);
			s[cnt] = val[cnt] = 0;
		}
		p = u, s[p] ++;
	}
	val[p] = x;
}

void Delete(int x) {
	int p = 0;
	for(int i = 30; i >= 0; i -- ) {
		int u = x >> i & 1;
		p = t[p][u];
		//记录节点p出现的次数
		-- s[p];
	}
}

int Query(int x) {
	int p = 0;
	for(int i = 30; i >= 0; i -- ) {
		int u = x >> i & 1;
		if(t[p][!u] && s[t[p][!u]]) p = t[p][!u];
		else p = t[p][u];
	}
	return x ^ val[p];
}

signed main(void) {
	IOS

	int ALL; cin >> ALL;
	while(ALL -- ) {
		cin >> n;
		res = 0; cnt = 0; memset(t, 0, sizeof t);

		//读入整数序列,同时将其插入Trie
		for(int i = 1; i <= n; i ++ ) cin >> a[i], Insert(a[i]);

		for(int i = 1; i <= n; i ++ ) {
			//将枚举的数字从Trie上删除
			Delete(a[i]);
			for(int j = i + 1; j <= n; j ++ ) {
				Delete(a[j]);
				res = max(res, Query(a[i] + a[j]));
				Insert(a[j]);
			}
			//删除后记得加上
			Insert(a[i]);
		}
		cout << res << endl;
	}

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值