P5283 [十二省联考 2019] 异或粽子 题解

\(Description\)

Luogu传送门

\(Solution\)

01trie + 堆

考虑对原数组做个前缀异或和,然后原问题就变成了找 \(k\) 对不都相同的点对,使它们异或起来的和最大。

显然我们要找出前 \(k\) 大的点对 \((l, r)\),但是 \(l\) 要小于 \(r\) ,非常恶心。

所以我们要把它翻一下变成矩阵,找前 \(2 \times k\) 大的点对,最后答案再除以 2 即可。

对于每一行 \(l\),先把最大的 \(val(l, r_1)\) 插到堆里,然后取堆顶加到答案里,再把堆顶元素所在行次大的的 \(val(l, r_2)\) 插到堆里,重复此操作。

注意要开 \(long \ long\)

\(Code\)

#include <bits/stdc++.h>
#define ll long long

using namespace std;

namespace IO{
    inline int read(){
        int x = 0;
        char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x;
    }

    template <typename T> inline void write(T x){
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace IO;

const int N = 5e5 + 10;
int n, k;
ll ans;
int a[N];
int trie[N << 5][2], siz[N << 5], tot;
struct node{
    int id, rk;
    ll val;
    bool operator < (const node &b) const{
        return val < b.val;
    }
};
priority_queue <node> q;

inline void insert(int x){
    int u = 0;
    for(int i = 31; i >= 0; --i){
        int t = (x >> i) & 1;
        siz[u]++;
        if(!trie[u][t]) trie[u][t] = ++tot;
        u = trie[u][t];
    }
    siz[u]++;
}

inline ll query(ll x, int rk){
    int u = 0;
    ll res = 0;
    for(int i = 31; i >= 0; --i){
        int t = (x >> i) & 1;
        if(!trie[u][t ^ 1]) u = trie[u][t];
        else if(rk <= siz[trie[u][t ^ 1]]) u = trie[u][t ^ 1], res |= (1ll << i);
        else rk -= siz[trie[u][t ^ 1]], u = trie[u][t];
    }
    return res;
}

signed main(){
    n = read(), k = read(); k <<= 1;
    for(int i = 1; i <= n; ++i) a[i] = read() ^ a[i - 1];
    for(int i = 0; i <= n; ++i) insert(a[i]);
    for(int i = 0; i <= n; ++i) q.push((node){i, 1, query(a[i], 1)});
    for(int i = 1; i <= k; ++i){
        node now = q.top(); q.pop();
        ans += now.val;
        if(now.rk < n) q.push((node){now.id, now.rk + 1, query(a[now.id], now.rk + 1)});
    }
    write((ans + 1) >> 1), puts("");
    return 0;
}

\[\_EOF\_ \]

posted @ 2021-12-29 17:58  xixike  阅读(51)  评论(0编辑  收藏  举报