本人没学过trie树(当然是忘了),做本题满头大汗,觉得极其困难,绞尽脑汁想出一种分治的做法。因为题解不让发了(全是trie树,毫无新意啊),于是就在讨论版发一个,看看能不能申精。
#include"bits/stdc++.h"
using namespace std;
int n,a[100010];
inline void read(int& k){
int s=0,x=1;
char c=getchar();
while(c>'9'||c<'0') {
if(c=='-') x=-1;
c=getchar();
}
while(c<='9'&&c>='0'){
s=s*10+int(c-'0');
c=getchar();
}
k=s*x;
}
int solve(int l1,int r1,int l2,int r2) {
if (l1>r1 || l2>r2) return 0;
int t1=a[l1]^a[r1],t2=a[l2]^a[r2];
while (t1!=(t1&-t1)) t1^=t1&-t1;
while (t2!=(t2&-t2)) t2^=t2&-t2;
if (t1==t2) {
if (t1==0) return a[l1]^a[l2];
int mid1=r1,mid2=r2;
while (a[mid1]&t1) mid1--;
while (a[mid2]&t2) mid2--;
return max(solve(l1,mid1,mid2+1,r2),solve(mid1+1,r1,l2,mid2));
}
if (t1<t2) {
int mid2=r2;
while (a[mid2]&t2) mid2--;
if ((a[l1]^a[l2])<(a[l1]^a[r2])) return solve(l1,r1,mid2+1,r2);
else return solve(l1,r1,l2,mid2);
} else {
int mid1=r1;
while (a[mid1]&t1) mid1--;
if ((a[l2]^a[l1])<(a[l2]^a[r1])) return solve(mid1+1,r1,l2,r2);
else return solve(l1,mid1,l2,r2);
}
}
int main() {
read(n);
//scanf("%d",&n);
for (int i=1;i<=n;i++) {
//scanf("%d",a+i);
read(a[i]);
}
sort(a+1,a+n+1);
int t=a[1]^a[n];
while (t!=(t&-t)) t^=t&-t; //取出不同的最高位1
int mid=n;
while (a[mid]&t) mid--;
printf("%d",solve(1,mid,mid+1,n));
return 0;
}
该做法就是先把所有数排序,排好后进行分治,思想就是每次找到最高位有意义的0/1(再往上都一样的话,xor后就都是0),然后在左右两边各取一个就是最优秀的。详见代码。 时间复杂度O(n(logAmax+logn))(瓶颈是排序和分治,分治和trie树本质相同,所以层数是logAmax的),暂时凭借优秀的常数在本题水的不行的数据下位列最优解