hdu5536 Chip Factory (01字典树+模拟删除路径 或者 暴力)

Chip Factory

hdu5536

Problem Description

给n个数的数组s
在一个数组中找出 (s[i]+s[j])^s[k] 最大的值,其中 i、j、k 各不相同。

Input

第一行给T表示案例数量
每个案例:
第一行给n
后面给n个数
1≤T≤1000
3≤n≤1000
0≤si≤109

Output

输出最大 (s[i]+s[j])^s[k] 最大的值,其中 i、j、k 各不相同。

Sample Input

2
3
1 2 3
3
100 200 300

Sample Output

6
400

分析:

容易想到建立01字典树然后枚举a[i]+a[j]
但是如果只是简单建树会因为无法辨别选出的用来异或的数的下标是否和i,j一样导致答案错误。
自己写的时候没想到可以加一个cnt标记数每个路径经过的次数(在插入过程中记录)。
在求解的过程中先删除a[i]和a[j](用完必须要恢复)。
具体操作是把他们经过路径的cnt减1。

ps:

暴力也能过,不过要用j=i+1,k=j+1稍微优化一下

01字典树代码:
 #include<iostream>
#include<cstdio>
#include<algorithm>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=1e3+5;
int all;
int val[maxm*32];
int nt[maxm*32][2];
int cnt[maxm*32];
ll a[maxm];
ll ffind(ll x){
    int now=0;
    for(int i=32;i>=0;i--){
        int v=(x>>i)&1;
        if(nt[now][v^1]&&cnt[nt[now][v^1]]){
            now=nt[now][v^1];
        }else{
            now=nt[now][v];
        }
    }
    return val[now];
}
void insertt(ll x){//插入
    int now=0;
    for(int i=32;i>=0;i--){
        int v=(x>>i)&1;
        if(nt[now][v]==0){
            nt[all][0]=nt[all][1]=0;
            val[all]=0;
            cnt[all]=0;
            nt[now][v]=all;
            all++;
        }
        now=nt[now][v];
        cnt[now]++;//经过次数加1
    }
    val[now]=x;
}
void init(){//初始化
    all=1;
    nt[0][1]=nt[0][0]=0;
}
void update(ll x,int add){//更新数据(删除以及恢复)
    int now=0;
    for(int i=32;i>=0;i--){
        int v=(x>>i)&1;
        now=nt[now][v];
        cnt[now]+=add;
    }
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        init();
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            insertt(a[i]);
        }
        ll ans=-1;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                update(a[i],-1);
                update(a[j],-1);
                ll t=a[i]+a[j];
                ans=max(ans,t^ffind(t));
                update(a[i],1);
                update(a[j],1);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
暴力:
#include<iostream>
#include<cstdio>
#include<algorithm>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=1e3+5;
int a[maxm];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int ans=-1;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                for(int k=j+1;k<=n;k++){
                    ans=max(ans,(a[i]+a[j])^a[k]);
                    ans=max(ans,(a[i]+a[k])^a[j]);
                    ans=max(ans,(a[j]+a[k])^a[i]);
                }
//                for(int k=1;k<=n;k++){//这样写的话时间比上面那个多了快4秒!
//                    if(k!=i&&k!=j){
//                        ans=max(ans,(a[i]+a[j])^a[k]);
//                    }
//                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值