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\n",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("\n"); } } }