zoukankan      html  css  js  c++  java
  • Codeforces 241B Friends 字典树

    Friends

    首先确定第 m 大的是谁, 建出字典树之后二分去check, 找到第 m 大之后, 在跑一次字典树去统计总和。

    为什么这个要取模啊, 卡了我半天。

    #include<bits/stdc++.h>
    #define LL long long
    #define LD long double
    #define ull unsigned long long
    #define fi first
    #define se second
    #define mk make_pair
    #define PLL pair<LL, LL>
    #define PLI pair<LL, int>
    #define PII pair<int, int>
    #define SZ(x) ((int)x.size())
    #define ALL(x) (x).begin(), (x).end()
    #define fio ios::sync_with_stdio(false); cin.tie(0);
    
    using namespace std;
    
    const int N = 5e4 + 10;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 1e9 + 7;
    const double eps = 1e-8;
    const double PI = acos(-1);
    
    template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
    template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
    template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
    template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;}
    
    const int LOG = 30;
    
    int n, a[N];
    LL m;
    LL sum, num;
    
    struct Trie {
        int ch[N * LOG][2], cnt[N * LOG];
        int f[N * LOG][30];
        int tot;
        void init() {
            tot = 1;
        }
        void ins(int x) {
            int u = 1;
            for(int i = LOG - 1; i >= 0; i--) {
                cnt[u]++;
                for(int j = LOG - 1; j >= 0; j--) f[u][j] += (x >> j & 1);
                if(!ch[u][x >> i & 1]) ch[u][x >> i & 1] = ++tot;
                u = ch[u][x >> i & 1];
            }
            for(int j = LOG - 1; j >= 0; j--) f[u][j] += (x >> j & 1);
            cnt[u]++;
        }
        PLL query(int x, int k, int op) {
            int u = 1;
            int now = 0;
            LL ans = 0;
            LL sum = 0;
            for(int i = LOG - 1; i >= 0 && u; i--) {
                if(x >> i & 1) {
                    if(now + (1 << i) >= k) {
                        ans += cnt[ch[u][0]];
                        if(op) {
                            for(int j = LOG - 1; j >= 0; j--) {
                                if(x >> j & 1) sum += 1LL * (1 << j) * (cnt[ch[u][0]] - f[ch[u][0]][j]);
                                else sum += 1LL * (1 << j) * f[ch[u][0]][j];
                            }
                        }
                        u = ch[u][1];
                    } else {
                        u = ch[u][0];
                        now += 1 << i;
                    }
                } else {
                    if(now + (1 << i) >= k) {
                        ans += cnt[ch[u][1]];
                        if(op) {
                            for(int j = LOG - 1; j >= 0; j--) {
                                if(x >> j & 1) sum += 1LL * (1 << j) * (cnt[ch[u][1]] - f[ch[u][1]][j]);
                                else sum += 1LL * (1 << j) * f[ch[u][1]][j];
                            }
                        }
                        u = ch[u][0];
                    } else {
                        u = ch[u][1];
                        now += 1 << i;
                    }
                }
            }
            if(now == k) ans += cnt[u], sum += 1LL * cnt[u] * now;
            return mk(ans, sum);
        }
    } trie;
    
    bool check(int x, int op) {
        sum = 0; num = 0;
        for(int i = 1; i <= n; i++) {
            PLL tmp = trie.query(a[i], x, op);
            num += tmp.fi; sum += tmp.se;
        }
        num /= 2; sum /= 2;
        return num >= m;
    }
    
    
    int main() {
        trie.init();
        scanf("%d%lld", &n, &m);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for(int i = 1; i <= n; i++) trie.ins(a[i]);
        int low = 0, high = (1 << 30) - 1, up = 0;
        while(low <= high) {
            int mid = low + high >> 1;
            if(check(mid, 0)) up = mid, low = mid + 1;
            else high = mid - 1;
        }
        check(up, 1);
        sum -= 1LL * (num - m) * up;
        printf("%lld", sum % mod);
        return 0;
    }
    
    /*
    */
  • 相关阅读:
    解决移动端页面在苹果端滑不到底部的问题
    js点击事件在苹果端失效的问题
    小程序开发基本步骤
    css多行文本省略号(...)
    js判断pc端和移动端的方法
    主流浏览器css兼容问题的总结
    让ie6对png透明图片支持起来
    ajax的探究与使用
    css3实现逐渐变大的圆填充div背景的效果
    js中setTimeout()时间参数设置为0的探讨
  • 原文地址:https://www.cnblogs.com/CJLHY/p/11051151.html
Copyright © 2011-2022 走看看