zoukankan      html  css  js  c++  java
  • Doubt [贪心, 0/1 Trie树]

    DoubtDoubt



    color{grey}{最初想法}

    按顺序构造 cic_i, 每次 贪心 地将 min(ab)min(a igoplus b) 取出, 作为 cic_i, 可以保证字典序最小,
    朴素实现是 O(N2)O(N^2) 的, 加上用 对第二个测试点 相同的数字加速处理 可以获得 50pts50pts .

    考虑直接找每个 aia_i 所匹配的 bib_i, 发现若 aia_i 找了 bib_i, 会影响到后面的 aja_jbib_i, 换句话说, 这样会有后效性 .


    color{red}{正解部分}

    不用关心 aia_i 匹配哪个 bib_i, 只需使得 cc较小值较小 即可实现 字典序最小,

    于是对 aabb 分别开一个 深度越大, 位数越低 的 0/1 Trie0/1 Trie树,
    从两颗 TrieTrie贪心 地从根节点同步向下走, 优先走权值相同的节点, 使得 cc越小值越小 即可 .


    color{red}{实现部分}

    • 根节点的下标赋为 11, 00 节点留作 虚点, 用来判边界 .
    • TrieTrie 中的 Add()Add() 函数, toto 要开 boolbool 类型 .
    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 6e6 + 10;
    
    struct Trie{
    
            int rot;
            int node_cnt;
    
            struct Node{ int ch[2], cnt; } T[maxn];
    
            void Add(int x){
                    int cur = rot;
                    for(reg int i = 30; i >= 0; i --){
                            bool to = (x & (1 << i));
                            if(!T[cur].ch[to]) T[cur].ch[to] = ++ node_cnt;
                            cur = T[cur].ch[to];
                            T[cur].cnt ++;
                    }
            }
    
    } t_a, t_b;
    
    int c_cnt;
    int c[maxn];
    
    void DFS(int k_1, int k_2, int sum, int pw){
            if(k_1) t_a.T[k_1].cnt --, t_b.T[k_2].cnt --;
            if(pw == 0){ c[++ c_cnt] = sum; return ; }
            while(t_a.T[t_a.T[k_1].ch[0]].cnt && t_b.T[t_b.T[k_2].ch[0]].cnt) DFS(t_a.T[k_1].ch[0], t_b.T[k_2].ch[0], sum, pw>>1);
            while(t_a.T[t_a.T[k_1].ch[1]].cnt && t_b.T[t_b.T[k_2].ch[1]].cnt) DFS(t_a.T[k_1].ch[1], t_b.T[k_2].ch[1], sum, pw>>1);
            while(t_a.T[t_a.T[k_1].ch[1]].cnt && t_b.T[t_b.T[k_2].ch[0]].cnt) DFS(t_a.T[k_1].ch[1], t_b.T[k_2].ch[0], sum|pw, pw>>1);
            while(t_a.T[t_a.T[k_1].ch[0]].cnt && t_b.T[t_b.T[k_2].ch[1]].cnt) DFS(t_a.T[k_1].ch[0], t_b.T[k_2].ch[1], sum|pw, pw>>1);
    }
    
    int N;
    
    int main(){
            N = read();
            t_a.rot = t_b.rot = 1;
            t_a.node_cnt = t_b.node_cnt = 1;
            for(reg int i = 1; i <= N; i ++) t_a.Add(read());
            for(reg int i = 1; i <= N; i ++) t_b.Add(read());
            DFS(1, 1, 0, 1<<30);
            std::sort(c+1, c+c_cnt+1);
            for(reg int i = 1; i <= c_cnt; i ++) printf("%d ", c[i]);
            return 0;
    }
    
  • 相关阅读:
    Java并发编程实战 第11章 性能与可伸缩性
    Lock的await/singal 和 Object的wait/notify 的区别(转载)
    线程阻塞和挂起(网络收集)
    Java并发编程实战 第10章 避免活跃性危险
    Java并发编程实战 第8章 线程池的使用
    Java并发编程实战 第6章 任务并行 第7章 取消与关闭
    Java并发编程实战 第5章 构建基础模块
    Java编程思想 第21章 并发
    Java并发编程实战 第4章 对象的组合
    Java并发编程实战 第3章 对象的共享
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822479.html
Copyright © 2011-2022 走看看