zoukankan      html  css  js  c++  java
  • 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\_ \]

  • 相关阅读:
    使用element-ui是下拉筛选选择
    vue 组件传值
    vue element 地址联动的使用
    vux scroller
    实时监听组件中路由的变化
    vuex的使用
    对移动端滚动高度的获取
    【转】ACM 取石子问题
    【转】ACM博弈知识汇总
    EOJ 2857 编辑距离
  • 原文地址:https://www.cnblogs.com/xixike/p/15746006.html
Copyright © 2011-2022 走看看