HDU 6625 three arrays
题意
给出a数组和b数组
c数组为
重排列数组使得得到的c数组字典序最小
思路
最小的为a[i]与b[j]相互对应
首先,从b数组中能找到与最小,我们称为的对应点
如何查找对应点,我们可以用字典树(Trie树),将每个数字看成30位01字符串
我们将a[i]与b[i]与其对应点相连
显然,若a[i]与b[j]对应,并且b[j]与a[i]对应,那么a[i]与b[j]组合一定是当前可选的最小的
证明:显然,若存在,与对应,矛盾
必定存在与相互对应
一个显然的事情是若个点和个点两两连线,必定存在回路
证明:不太清楚的童鞋可以尝试构造一下无回路的情况,会发现最后一个点必定会形成回路
不会存在路径超过2的回路
显然路径为2的回路存在是合理的,即为相互对应
对于路径超过2的路径
如下图,若存在a[x]对应b[z],b[z]对应a[y],连接a[x]与b[z]的异或值大于b[z]与a[y]的异或值
下面我们简称一条边的值为一条边相连的两个值的异或
以下图为例,若存在回路,a[x]b[z]边大于a[y]b[z],必定再次回到a[x]b[z]边造成矛盾
,矛盾!
具体实现
- 若栈区为空,随便加一个点入栈
- 若栈顶的对应点不在栈中,将其入栈
- 若栈顶的对应点在栈中,必定为栈定第二个(最爱top元素的元素)
我们以下图来模拟以下该过程
1、将a[1]入栈(随便加一个)
栈区:
2、将b[2]入栈(将栈顶元素最爱的元素入栈)
栈区:
3、将a[3]入栈(将栈顶元素最爱的元素入栈)
栈区:
3、将b[3]入栈(将栈顶元素最爱的元素入栈)
栈区:
4、将a[3]和b[3]出栈(发现 栈顶元素 最爱的元素 即为 最爱栈顶元素 的元素,相亲相爱,牵手成功)
栈区:
5、将a[2]入栈(b[2]移情别恋,爱上a[2])
栈区:
6、将b[1]入栈(将栈顶元素最爱的元素入栈)
栈区:
7、将a[2]和b[1]出栈(发现 栈顶元素 最爱的元素 即为 最爱栈顶元素 的元素,相亲相爱,牵手成功)
栈区:
8、将a[1]和b[2]出栈(最爱你的人永远在你后面等你,单相思也会有结果qwq)
栈区:空
pii stack[maxn * 2];//first存大小,second存在哪个数组中,0表示a数组,1表示b数组
int top = 0;
int sum = 2 * n;
while (sum) {
if (!top) { //栈区为空,随便从a数组中找一个数塞进去,估且就找个最爱1的吧
stack[++top] = pii(T[0].find(1), 0);
continue;
}
int symbol = T[stack[top].second ^ 1].find(stack[top].first);//symbol表示栈顶元素最爱元素
if (top == 1 || stack[top - 1].first != symbol) //栈顶元素最爱元素不在栈中
stack[top + 1] = pii(symbol, stack[top].second ^ 1), //入栈
top++;
else {
res.push_back(stack[top].first ^ stack[top - 1].first); //牵手成功双双出栈
T[stack[top].second].insert(stack[top].first, -1);
T[stack[top - 1].second].insert(stack[top - 1].first, -1);
sum -= 2, top -= 2;
}
}
Trie树找最爱
插入与删除
一切尽在不言注释中
void insert(int str, int val) { //val=1,表示插入一个数,val=-1表示删除一个数
int position = root; //初始化位置
for (int i = 29; i >= 0; i--) { //将每一位从高到低插入
int symbol = (str >> i) & 1; //提取二进制位
if (!tree[position].son[symbol])//创建新节点
tree[position].son[symbol] = ++num;
position = tree[position].son[symbol];
tree[position].mark += val; //每一位都要记录有无,便于下方的查找
}
}
查找
int find(int str) {
int position = root, w = 0;
for (int i = 29; i >= 0; i--) { //按二进制位从高到底查找
int symbol = (str >> i) & 1;
if (!tree[position].son[symbol] || !tree[tree[position].son[symbol]].mark)
symbol ^= 1; //若该位symbol不存在,或者已被用光,那么选择另一个,0^1=1,1^1=0
position = tree[position].son[symbol]; //迭代寻找
w |= (symbol<< i); //将该位存入答案
}
return w;
}
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#pragma warning (disable:4996)
typedef pair<int, int> pii;
const int maxn = 101000;
struct Tree {
Tree() {
son[0] = son[1] = mark = 0;
}
int mark; //标记
int son[2]; //此处只考虑小写字母
};
struct Trie {
int root, num; //根节点永久为0
Tree tree[maxn * 33];
Trie() {
root = num = 0;
memset(tree, 0, sizeof(0));
}
void init() {
Tree st;
fill(tree, tree + num + 1, st);
root = num = 0;
}
void insert(int str, int val) {
int position = root; //初始化位置
for (int i = 29; i >= 0; i--) {
int symbol = (str >> i) & 1; //转化函数,视情况而定
if (!tree[position].son[symbol])//创建新节点
tree[position].son[symbol] = ++num;
position = tree[position].son[symbol];
tree[position].mark += val;
}
}
int find(int str) {
int position = root, w = 0;
for (int i = 29; i >= 0; i--) {
int symbol = (str >> i) & 1;
if (!tree[position].son[symbol] || !tree[tree[position].son[symbol]].mark) symbol ^= 1;
position = tree[position].son[symbol];//迭代寻找
w |= (symbol<< i);
}
return w;
}
}T[2];
int n;
void Read() {
T[0].init();
T[1].init();
scanf("%d", &n);
int x;
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
T[0].insert(x, 1);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
T[1].insert(x, 1);
}
}
pii stack[maxn * 2];
int top = 0;
vector<int> res;
void slove() {
res.clear();
top = 0;
int sum = 2 * n;
while (sum) {
if (!top) {
stack[++top] = pii(T[0].find(1), 0);
continue;
}
int symbol = T[stack[top].second ^ 1].find(stack[top].first);
if (top == 1 || stack[top - 1].first != symbol)
stack[top + 1] = pii(symbol, stack[top].second ^ 1),
top++;
else {
res.push_back(stack[top].first ^ stack[top - 1].first);
T[stack[top].second].insert(stack[top].first, -1);
T[stack[top - 1].second].insert(stack[top - 1].first, -1);
sum -= 2, top -= 2;
}
}
}
int main() {
int t; scanf("%d", &t);
while (t--) {
Read();
slove();
sort(res.begin(), res.end());
for (int i = 0; i < res.size(); i++)
printf("%d%c", res[i], i == res.size() - 1 ? '\n' : ' ');
}
}