Chip Factory
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;
}