01字典树加强版HDU 5536

01字典树加强版HDU 5536

http://acm.hdu.edu.cn/showproblem.php?pid=5536

  1. 简化版题意:
    在一个数组中找出 (s[i]+s[j])^s[k] 最大的值,其中 i、j、k 各不相同。

  2. 这个题目我们就不能直接套用模板了,问题出在哪里?是因为i、j、k不能相同,所以直接查询tire树会出现问题。怎么办?一个很直观的想法是删除。对k建trie树,枚举i、j,然后将i、j在trie树中删除。

  3. 考虑如何删除,我们用一个num数组记录每一个结点出现的次数(注意是每一个结点而不是结尾的结点,因为如果i,j两个位置的数字不能使用,那么在tire树上所有关于他的结点都不能使用),在每次insert的时候增加num,在每次删除的时候减少num,在最后查询的时候判断num是否为0代表当前树上这个结点是否可以使用。说到这里,这个题的大致思路就说完了,下面直接上代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define mk(a,b) make_pair(a,b)
#define ll long long
#define N 1010	
using namespace std;
ll tot,ch[N*32][3],val[N*32],num[N*32],t,a[N];
void init()
{
	tot=1;
	ch[0][1]=0;ch[0][0]=0;
}
void insert(ll x)
{
	ll u=0;
	for(ll i=32;i>=0;i--)
	{
		ll v=(x>>i)&1;
		if(!ch[u][v])
		{
			ch[tot][0]=0;ch[tot][1]=0;
			val[tot]=0;
			num[tot]=0;
			ch[u][v]=tot++;
		}
		u=ch[u][v];
		num[u]++;
	}
	val[u]=x;
}
void del(ll x,ll add)
{
	ll u=0;
	for(ll i=32;i>=0;i--)
	{
		ll v=(x>>i)&1;
		u=ch[u][v];
		num[u]+=add;
	}
}
ll query(ll x)
{
	ll u=0;
	for(ll i=32;i>=0;i--)
	{
		ll v=(x>>i)&1;
		if(ch[u][v^1]&&num[ch[u][v^1]]) u=ch[u][v^1];
		else  u=ch[u][v];
	}
	return x^val[u];
}
int main()
{
	scanf("%lld",&t);
	for(ll k=1;k<=t;k++)
	{
		ll n,ans=0;
		init();
		scanf("%lld",&n);
		for(ll i=1;i<=n;i++)
		{
		  scanf("%lld",&a[i]);
		  insert(a[i]);
		}
		for(ll i=1;i<=n;i++)
		  for(ll j=i+1;j<=n;j++)
		  {
		  	  del(a[i],-1);del(a[j],-1);
		  	  ans=max(ans,query(a[i]+a[j]));
		  	  insert(a[i]);insert(a[j]);
		  }
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42110318/article/details/83650839