Chip Factory(字典树,学会将路暂时删除)

113 篇文章 1 订阅

题目链接:Chip Factory

题目大意:给你n个数,从中选出三个数a,b,c,使得(a+b)异或c最大。

思路:先建立字典树,选出两个数,先暂时删除,然后找出与其异或的最大值。

下面是代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int maxn=1009;
int sum,coun;

struct node
{
    int l,r;//左(右)节点位置
    int sum_l,sum_r;//记录有多少个数是从这个节点的左(右)经过
    int inq;//最终这个数是几。
} dis[100*maxn];
int a[maxn],wei[33];


void build(int x)//建立字典树
{
    int now=0;
    for(int i=30; i>=0; i--)
    {
        if(wei[i]&x)
        {
            if(dis[now].r==-1)
            {
                dis[coun].inq=dis[coun].sum_r=dis[coun].sum_l=0;
                dis[coun].r=dis[coun].l=-1;
                dis[now].r=coun++;
            }
            dis[now].sum_r++;
            now=dis[now].r;
        }
        else
        {
            if(dis[now].l==-1)
            {
                dis[coun].inq=dis[coun].sum_r=dis[coun].sum_l=0;
                dis[coun].l=dis[coun].r=-1;
                dis[now].l=coun++;
            }
            dis[now].sum_l++;
            now=dis[now].l;
        }
    }
    dis[now].inq=x;
}

int dele(int x)//暂时删除a[i](a[j])
{
    int now=0;
    for(int i=30; i>=0; i--)
    {
        if(wei[i]&x)
        {
            dis[now].sum_r--;
            if(dis[now].sum_r==0)//没有数从这里通过,说明只有x这个数会经过这里,返回此处的位置
            {
                int f=dis[now].r;
                dis[now].r=-1;
                return f;
            }
            now=dis[now].r;
        }
        else
        {
            dis[now].sum_l--;
            if(dis[now].sum_l==0)
            {
                int f=dis[now].l;
                dis[now].l=-1;
                return f;
            }
            now=dis[now].l;
        }
    }
}
int match(int x)//查找与(a[i]+a[j])异或的最大值
{
    int now=0;
    for(int i=30; i>=0; i--)
    {
        if(((wei[i]&x)&&dis[now].l!=-1)||dis[now].r==-1)
            now=dis[now].l;
        else now=dis[now].r;
    }
    return dis[now].inq;
}
void restore(int x,int f)//回复a[i](a[j])这个数
{
    int now=0;
    for(int i=30; i>=0; i--)
    {
        if(wei[i]&x)
        {
            dis[now].sum_r++;
            if(dis[now].r==-1)
            {
                dis[now].r=f;
                return ;
            }
            now=dis[now].r;
        }
        else
        {
            dis[now].sum_l++;
            if(dis[now].l==-1)
            {
                dis[now].l=f;
                return ;
            }
            now=dis[now].l;
        }
    }
}
int main()
{
    int t;
    wei[0]=1;
    for(int i=1; i<31; i++)
        wei[i]=wei[i-1]*2;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        sum=0,coun=1;
        dis[0].l=dis[0].r=-1;
        dis[0].inq=0;
        dis[0].sum_l=dis[0].sum_r=0;
        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
            build(a[i]);//建立字典树
        }
        for(int i=0; i<n; i++)//遍历所有的情况(a[i]+a[j])
        {
            int x=dele(a[i]);//先删除,a[i],x代表a[i]这个节点的位置
            for(int j=i+1; j<n; j++)
            {
                int y=dele(a[j]);//删除,a[j],y代表a[j]这个节点的位置
                int f=match(a[i]+a[j]);
                sum=max(sum,f^(a[i]+a[j]));
                restore(a[j],y);//还原a[j],还原是有先后顺序的,一定是先还原a[j],再还原a[i]
            }
            restore(a[i],x);//还原a[i]
        }
        printf("%d\n",sum);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值