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' : ' ');
}
}