zoukankan      html  css  js  c++  java
  • 【题解】「CF241B」Friends

    「CF241B」Friends

    trie上乱玩.

    传送门

    异或粽子加强版.

    正篇

    我们可以先求出第$k$大的异或值$K$(在那之前k*=2,方便处理两个顺序相反的数对产生的贡献),再计算所有比$K$大的异或值的和。

    对于求$K$,我们可以建一棵$01trie$,然后在从高到低扫的同时记录每个数当前到达的树点(初始为根),每次用它们计算当前位为$1$的$cnt$,判断$cnt$与$k$的大小关系,并根据结果计算$K$的这一位和更新树点们(?)。

    然后我们可以发现,对于一个数$x>K$,一定在二进制下有第$i$位$x$为$1$,$K$为$0$,而第大于$i$位有$x$取值$=$$K$取值。

    于是问题变得简单了:同样的方法记录树点,若当前位$K$为$0$,则我们计算当前异或值为$1$对答案的贡献。这个东西是在$trie$上子树进行对答案的计算的,所以可以记录子树里每一位不同取值的个数,但是不太好算QAQ。我们发现可以对原数组排序并按该顺序进行插入,于是子树对应的区间就是连续的,可以在原数组上前缀和简化算法了!于是这道题就过了(。

    代码

     大概就和题解里讲的差不多,但细节蛮多的。(借鉴了不少别人博客QAQ

    #include <bits/stdc++.h>
    #define Ri register int
    #define FOR(i, j, k) for(Ri i = (j); i <= (k); i++)
    #define DEC(i, j, k) for(Ri i = (j); i >= (k); i--)
    #define ll long long int
    using namespace std;
    
    const int maxn = 5e4 + 10, maxk = 32, M = 1e9 + 7, iv2 = 5e8 + 4;
    int n, a[maxn];
    int ch[maxn * maxk][2], lb[maxn * maxk], rb[maxn * maxk], rt, nc;
    int sum[maxn][maxk][2], siz[maxn * maxk];
    ll m;
    
    inline void insert(int x) {
        if(!rt) rt = ++nc, lb[rt] = 1, rb[rt] = n;
        int k = rt;
        siz[rt]++;
        DEC(d, 29, 0) {
            if(!ch[k][(a[x] >> d) & 1]) ch[k][(a[x] >> d) & 1] = ++nc, lb[ch[k][(a[x] >> d) & 1]] = x;
            k = ch[k][(a[x] >> d) & 1];
            rb[k] = x;
            siz[k]++;
        }
    }
    
    inline ll calc(int k, int v) {
        if(!k) return 0;
        ll res = 0;
        DEC(d, 29, 0) {
            ll t = sum[rb[k]][d][((v >> d) & 1) ^ 1] - sum[lb[k] - 1][d][((v >> d) & 1) ^ 1];
            res = (res + t * (1 << d) % M) % M;
        }
        return res;
    }
    
    int to[maxn * maxk];
    
    int main() {
        scanf("%d%lld", &n, &m);
        m <<= 1LL;
        FOR(i, 1, n) scanf("%d", &a[i]);
        sort(a + 1, a + n + 1);
        lb[0] = 1, rb[0] = 0;
        FOR(i, 1, n) insert(i);
        
        //get sum[]
        FOR(i, 1, n) {
            FOR(d, 0, 29) {
                sum[i][d][0] = sum[i - 1][d][0] + (((a[i] >> d) & 1) == 0);
                sum[i][d][1] = sum[i - 1][d][1] + (((a[i] >> d) & 1) == 1);
            }
        }
        
        //get k-th xor
        int low = 0;
        FOR(i, 1, n) to[i] = rt;
        DEC(d, 29, 0) {
            ll cnt = 0;
            FOR(i, 1, n) cnt += siz[ch[to[i]][((a[i] >> d) & 1) ^ 1]];
            if(cnt >= m) {
                low |= (1 << d);
                FOR(i, 1, n) {
                    to[i] = ch[to[i]][((a[i] >> d) & 1) ^ 1];
                }
            }else {
                m -= cnt;
                FOR(i, 1, n) {
                    to[i] = ch[to[i]][(a[i] >> d) & 1];
                }
            }
        }
        
        //Answer!
        ll ans = m % M * low % M;
        FOR(i, 1, n) to[i] = rt;
        DEC(d, 29, 0) {
            int x = (low >> d) & 1;
            if(!x) {
                FOR(i, 1, n) {
                    ans = (ans + calc(ch[to[i]][((a[i] >> d) & 1) ^ 1], a[i])) % M;
                }
            }
            FOR(i, 1, n) {
                to[i] = ch[to[i]][((a[i] >> d) & 1) ^ x];
            }
        }
        printf("%lld", ans * iv2 % M);
        return 0;
    }
  • 相关阅读:
    Python subprocess- call、check_call、check_output
    Java Annotation认知(包括框架图、详细介绍、示例说明) (转)
    NVME SSD vs SATA SSD(转)
    scala中“_”的用法
    maven scope 'provided' 和 ‘compile’的区别
    scala tuple中的syntactic sugar
    Scala中的"null" 和“_”来初始化对象
    scala可变长度参数(转)
    Java中的Builder模式
    Scala中“=>”用法及含义
  • 原文地址:https://www.cnblogs.com/Asd-Okuu/p/13922062.html
Copyright © 2011-2022 走看看