Codeforces Round #779 (Div. 2) D 388535

D2. 388535 (Hard Version)

Codeforces Round #779 (Div. 2) D 388535_第1张图片
这里直接上 D 2 D2 D2 的做法吧。我们可以知道 l ⊕ x l\oplus x lx 一定在 a a a 中,所以对于 ( a [ i ] ⊕ l ) (a[i]\oplus l) (a[i]l) (1<=i<=r-l+1) ,总有一个是 x x x 。我们现在设 b [ i ] = ( a [ i ] ⊕ l ) b[i]=(a[i]\oplus l) b[i]=(a[i]l) ,那么我们怎么判断 b [ i ] b[i] b[i] 是不是 x x x 呢?首先我们要知道原序列是一个排列,所以不会有相同的数字,且当前序列是通过原序列异或上同一个数字得到的,所以当前序列也不会有相同的数字,所以当前的序列再异或上一个相同的数字也不可能有相同的数字。

那么想要知道 b [ i ] b[i] b[i] 是否可以作为 x x x ,我们只要知道:
m i n { b [ i ] ⊕ a [ j ] ∣ 1 ≤ j ≤ r − l + 1 } = = l   ? min\{b[i]\oplus a[j]\mid 1\leq j\leq r-l+1\} ==l\ ? min{b[i]a[j]1jrl+1}==l ?
m a x { b [ i ] ⊕ a [ j ] ∣ 1 ≤ j ≤ r − l + 1 } = = r   ? max\{b[i]\oplus a[j]\mid 1\leq j\leq r-l+1\}==r\ ? max{b[i]a[j]1jrl+1}==r ?
因为如果最小值为 l l l ,最大值为 r r r ,且我们知道每个数都不同,那不自然就是 [ l , r ] [l,r] [l,r] 的一个排列了么。求上述最小值和最大值就是经典的 01 01 01 字典树问题了。

#include

using namespace std;

const int N = 5e5 + 10;

int a[N];
int tot, nxt[20*N][2];

void clear() {
    tot = 0;
    nxt[0][0] = nxt[0][1] = 0;
}

void insert(int x) {
    int rt = 0;
    for (int i = 20; i >= 0; --i) {
        int cur = (x >> i & 1);
        if (!nxt[rt][cur]) {
            nxt[rt][cur] = ++tot;
            nxt[tot][0] = nxt[tot][1] = 0;    
        }
        rt = nxt[rt][cur];
    }
}

int query_min(int x) {
    int rt = 0, ans = 0;
    for (int i = 20; i >= 0; -- i) {
        int cur = (x >> i & 1);
        int need = cur;
        if (!nxt[rt][need]) {
            ans = (ans << 1) | 1;
            need = !need;
        }
        else {
            ans = (ans << 1);
        }
        rt = nxt[rt][need];
    }
    return ans;
}

int query_max(int x) {
    int rt = 0, ans = 0;
    for (int i = 20; i >= 0; -- i) {
        int cur = (x >> i & 1);
        int need = (cur ^ 1);
        if (!nxt[rt][need]) {
            ans = (ans << 1);
            need = !need;
        }
        else {
            ans = (ans << 1) | 1;
        }
        rt = nxt[rt][need];
    }
    return ans;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int T; scanf("%d", &T);
    int n;
    while(T--) {
        int l, r; scanf("%d%d", &l, &r);
        for (int i = l; i <= r; ++i) {
            scanf("%d", &a[i]);
            insert(a[i]);
        }
        int x;
        for (int i = l; i <= r; ++i) {
            if (query_min(a[i] ^ l) == l && query_max(a[i] ^ l) == r) {  
                x = (a[i] ^ l);
                break;
            }
        }
        clear();
        printf("%d\n", x);
        // for (int i = l; i <= r; ++i) {
        //     cout << (x ^ a[i]) << ' ';
        // }
        // cout << endl << endl;
    }
}

你可能感兴趣的:(数据结构,思维,c语言,分类,算法)