• 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\_ \]

  • 相关阅读:
    PHP工程师学Python数据类型
    通过PHP与Python代码对比浅析语法差异
    “adobe premiere中画面和声音不同步” 解决方法
    Web安全之XSS Platform搭建及使用实践
    使用docker快速搭建Permeate渗透测试系统实践
    Web安全开发规范手册V1.0
    遭受刷验证码攻击后的企安建设规划感想
    基于Docker搭建Jumpserver堡垒机操作实践
    使用PHP结合Ffmpeg快速搭建流媒体服务实践
    通过代码审计找出网站中的XSS漏洞实战(三)
  • 原文地址:https://www.cnblogs.com/xixike/p/15746006.html
Copyright © 2020-2023  润新知