zoukankan      html  css  js  c++  java
  • hdu多校第五场1002 (hdu6625) three arrays 字典树/dfs

    题意:

    给你两个序列a,b,序列c的某位是由序列a,b的此位异或得来,让你重排序列ab,找出字典序最小的序列c。

    题解:

    如果能找到a,b序列中完全一样的值当然最好,要是找不到,那也尽量让低位不一样。

    因此,将两个序列中元素的二进制视作字符串,建字典树。

    在两棵字典树上,贪心地找让当前位一样的。

    每找c的一位,dfs一遍,dfs过程中剪掉已经因为构造c而用掉的子树,构造序列c。

    然后爆wa。。。

    我造了好几组测例,发现贪心并不能找出当前位的最优解,比如dfs到两棵字典树上的某个点,这两个节点都既有左儿子,又有右儿子,那么到底是都向左走更优,还是都向右走更优,字典树上没有这个信息。

    比如数据  3  1,0,2  2,4,1  程序打死都要给出我0,4,0的结果

    直到有人提醒我:“你再把c数组排个序不就行了嘛”

    我:“。。。。。。”

    那么,不管不顾地贪心,只要dfs到的两点都能向1的方向走,那就都向1的方向走,因为当都向1这个方向走这棵子树此次被剪掉后,以后一定能构造出都向0的方向走的最优解。

    只要再把c排序一遍,就不用计较此点最优解是先构造出来的还是后构造出来的了。

    #include<iostream>
    #include<cstring> 
    #include<algorithm>
    using namespace std;
    //const int MAXN=1<<30;
    struct Node{
        int to[2];
        bool end;
        int size;
    };
    int c[100005];
    struct Trie{
        Node node[31*100005];
        int nodenum;
        void init(int n){
            for(int i=0;i<=n*31;i++)memset(&node[i],0,sizeof (Node));
            nodenum=1;
        }
        void push(int n){
            int nowid=1;
            for(int i=30;i>=0;i--){
                ++node[nowid].size;
                bool t=(n>>i)&1;
                if(node[nowid].to[t]==0){
                    node[nowid].to[t]=++nodenum;
                    nowid=nodenum;
                }else{
                    nowid=node[nowid].to[t];
                }
    //            n>>=1;
            }
            ++node[nowid].size;
            node[nowid].end=1;
        }
    }trie1,trie2;
    int find1(){
        int id1=1,id2=1;
        int ans=0;
        int i=0;
        bool to10,to11,to20,to21;
        while(!trie1.node[id1].end && !trie2.node[id2].end){
            ans<<=1;
            --trie1.node[id1].size;
            --trie2.node[id2].size;
            to10=trie1.node[trie1.node[id1].to[0]].size>0;
            to11=trie1.node[trie1.node[id1].to[1]].size>0;
            to20=trie2.node[trie2.node[id2].to[0]].size>0;
            to21=trie2.node[trie2.node[id2].to[1]].size>0;
            if(to11 && to21){
                id1=trie1.node[id1].to[1];
                id2=trie2.node[id2].to[1];
            }else if(to10 && to20){
                id1=trie1.node[id1].to[0];
                id2=trie2.node[id2].to[0];
            }else if(to10 && to21){
                id1=trie1.node[id1].to[0];
                id2=trie2.node[id2].to[1];
                ++ans;
            }else if(to11 && to20){
                id1=trie1.node[id1].to[1];
                id2=trie2.node[id2].to[0];
                ++ans;
            }
            ++i;
        }
        --trie1.node[id1].size;
        --trie2.node[id2].size;
        return ans;
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            int n,tmp;
            scanf("%d",&n);
            trie1.init(n);trie2.init(n);
            for(int i=1;i<=n;i++){
                scanf("%d",&tmp);
                trie1.push(tmp);
            }
            for(int i=1;i<=n;i++){
                scanf("%d",&tmp);
                trie2.push(tmp);
            }
    //        for(int i=1;i<=trie1.nodenum;i++){
    //            printf("%d %d %d %d
    ",trie1.node[i].size,trie1.node[i].to[0],trie1.node[i].to[1],trie1.node[i].end);
    //        }
            for(int i=1;i<=n;i++){
                c[i]=find1();
            }
            sort(c+1,c+1+n);
            for(int i=1;i<=n;i++){
                printf("%d",c[i]);
                if(i<n)printf(" ");
                else printf("
    ");
            }
        }
    }
  • 相关阅读:
    c语言:猴子吃桃问题
    c语言:输入任意数求该数的阶乘
    (整理三)高并发架构思路,附十万定时任务执行解决方案
    (整理4)RPC服务和HTTP服务简单说明
    .NET Core和Swagger 生成 Api 文档转
    (整理二)读取大日志文件
    (整理一)理解分布式事务,高并发下分布式事务的解决方案-附索引的利弊
    2016年结
    2013年结
    2017年结
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11310374.html
Copyright © 2011-2022 走看看