题意:
给定两个长为n的数组a和b;
重新排列a和b,生成数组c,c[i]=a[i] xor b[i];
输出字典序最小的c数组。
分析:
将a中的数插入一颗01字典树a中;
将b中的数插入一颗01字典树b中;
在trie树上查找n次,每次同时在a和b中下移一层;
if 能同时走0,则同时走0;
else if 能同时走1,则同时走1;
else if 树a能走0&&树b能走1,则a走0、b走1;
else if 树a能走1&&树b能走0,则a走1、b走0;
else 向c中插入一个新数为这两个节点的异或值;
最后对c排序。
复杂度O(T*n*30)
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6+5; typedef long long LL; struct Trie01{ int ch[35 * maxn][2]; int cnt[35*maxn]; int node_cnt; inline void init(){ node_cnt = 1; memset(ch[0],0,sizeof(ch[0])); } inline void Insert(LL x){ int cur = 0; for(int i = 30;i >= 0;--i){ int idx = (x >> i) & 1; if(!ch[cur][idx]){ memset(ch[node_cnt],0,sizeof(ch[node_cnt])); ch[cur][idx] = node_cnt; cnt[node_cnt++]=0; } cur = ch[cur][idx]; cnt[cur]++; } } }t1,t2; vector<int> ans; void solve(int N){ int u1,u2; while(N--) { u1 = u2 = 0; int x = 0; for(int p = 30; p >= 0; p--) { if(t1.cnt[t1.ch[u1][0]] && t2.cnt[t2.ch[u2][0]]) { t1.cnt[t1.ch[u1][0]]--; t2.cnt[t2.ch[u2][0]]--; u1 = t1.ch[u1][0]; u2 = t2.ch[u2][0]; } else if(t1.cnt[t1.ch[u1][1]] && t2.cnt[t2.ch[u2][1]]) { t1.cnt[t1.ch[u1][1]]--; t2.cnt[t2.ch[u2][1]]--; u1 = t1.ch[u1][1]; u2 = t2.ch[u2][1]; } else if(t1.cnt[t1.ch[u1][0]] && t2.cnt[t2.ch[u2][1]]) { t1.cnt[t1.ch[u1][0]]--; t2.cnt[t2.ch[u2][1]]--; u1 = t1.ch[u1][0]; u2 = t2.ch[u2][1]; x ^= (1 << p); } else { t1.cnt[t1.ch[u1][1]]--; t2.cnt[t2.ch[u2][0]]--; u1 = t1.ch[u1][1]; u2 = t2.ch[u2][0]; x ^= (1 << p); } } ans.push_back(x); } return ; } int main(){ int _;scanf("%d",&_); while(_--){ int n;scanf("%d",&n); t1.init(),t2.init(); for(int i=1;i<=n;i++){ int x;scanf("%d",&x); t1.Insert(x); } for(int i=1;i<=n;i++){ int x;scanf("%d",&x); t2.Insert(x); } ans.clear(); solve(n); sort(ans.begin(),ans.end()); printf("%d",ans[0]); for(int i=1;i<ans.size();i++) { printf(" %d",ans[i]); }puts(""); } }