题解中没提到的一种分治的做法
查看原帖
题解中没提到的一种分治的做法
131593
Woxuanyi楼主2024/10/18 02:52

本人没学过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的),暂时凭借优秀的常数在本题水的不行的数据下位列最优解

2024/10/18 02:52
加载中...