Codeforces Round #779 D2. 388535 (Hard Version) (01字典树)

Codeforces Round #779 D2. 388535 (Hard Version) (01字典树)


题目

题意大概就是给一个l, r, 然后选一个数x对l-r的排列pi每一项进行异或操作,得到数组a[], ai = pi ^ x。现在输入l, r和操作后的数组a[],让你求它们异或的数 X 是什么?

思路

  • 首先根据异或性质pi ^ x = ai, 那么ai ^ x = pi,所以我们可以暴力遍历这个x和a[]进行异或,然后验证是否是l-r排列即可,显然这个方法O(n^2logn)太暴力了。
  • 进一步优化:我们只需要 max(ai ^ x) = l, min(ai ^ x) = r 即可,显然这个方法复杂度没变只是验证简单了。现在复杂度大头主要是x和每个ai异或的O(n)的复杂度,有没有方法能快速求出异或最大值,最小值? 这里就使用01字典树,它主要用于解决求异或最值问题,如给出x和数组a[],求x^ai的最值,复杂度为O(logn)。
  • 使用01字典树我们解决原问题,由于遍历x太多仍然会超时,我们发现我们要找 ai ^ x = l,那么这个x肯定在 ai ^ l 得到的集合中。
  • 最终我们遍历x = ai ^ l, 对每个x,使用01字典树求出max, min 如果分别等于l,r, 则这个x就是我们要的答案。

参考博客

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<string>
#include<set>
#include<fstream>
using namespace std;
#define rep(i, a, n) for(int i = a; i <= n; ++ i)
#define per(i, a, n) for(int i = n; i >= a; -- i)
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<ll, int> PLI;
typedef pair<ll, ll> PLL;
const int N = 2e6 + 50;
const int mod = 998244353;
const double Pi = acos(- 1.0);
const ll INF = 1e12;
const int G = 3, Gi = 332748118;
ll qpow(ll a, ll b, ll p) { ll res = 1; while(b){ if(b & 1) res = (res * a) % p; a = (a * a) % p; b >>= 1;} return res % p; }
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }

ll l, r, n;
ll a[N];
ll idx;

//建树
void insert(ll x, vector<vector<ll> > &nxt){
    ll now = 0;
    for(int i = 31; i >= 0; -- i){
        int y = (x >> i) & 1;
        if(!nxt[now][y]) nxt[now][y] = ++ idx;
        now = nxt[now][y];
    }
}

ll query_max(ll x, vector<vector<ll> > &nxt){
    ll now = 0, res = 0;
    for(int i = 31; i >= 0; -- i){
        int y = (x >> i) & 1;
        if(nxt[now][y ^ 1]){
            res += (1 << i);
            now = nxt[now][y ^ 1];
        }else now = nxt[now][y];
    }
    return res;
}

ll query_min(ll x, vector<vector<ll> > &nxt){
    ll now = 0, res = 0;
    for(int i = 31; i >= 0; -- i){
        int y = (x >> i) & 1;
        if(nxt[now][y]) now = nxt[now][y];
        else {
            res += (1 << i);
            now = nxt[now][y ^ 1];
        }
    }
    return res;
}

void solve(){
    idx = 0;
    scanf("%lld%lld",&l ,&r);
    n = r - l + 1;
    vector<vector<ll> > nxt(n * 32, vector<ll>(2, 0));
    for(int i = 1; i <= n; ++ i){
        scanf("%lld",&a[i]);
        insert(a[i], nxt);
    }

    for(ll i = 1; i <= n; ++ i) {
        ll ans = a[i] ^ l;
        ll L = query_min(ans, nxt);
        ll R = query_max(ans, nxt);
        if(L == l && R == r) {
            printf("%lld\n",ans);
            return;
        }
    }
}

int main() {
    freopen("temp.in", "r", stdin);
    freopen("temp.out", "w", stdout);
    int T; scanf("%d",&T);
    while(T --){
        solve();
    }
    return 0;
}

posted @ 2022-04-02 11:25  A_sc  阅读(58)  评论(0编辑  收藏  举报