異或數組


也許更好的閱讀體驗

\(\mathcal{Description}\)

給你兩個長度為\(n\)的數組\(a,b\)
你需要把\(a,b\)兩個數組分別按某種方式排序
然后令\(c_i=a_i\ xor\ b_i\),你要使\(c\)的字典序最小
請輸出\(c\)這個數組
\(n\leq200000\ a_i,b_i\leq 2^{30}\)

\(\mathcal{Solution}\)

\(a,b\)這兩個數組的數分別放到一個\(01Trie\)樹里面
並記下每個點的位置有多少串經過
然后考慮構造\(c\)
兩個\(Trie\)樹一起開始跑,從\(2^{30}\)開始考慮
先考慮兩邊異或起來為\(0\)的情況,再考慮兩邊異或起來為\(1\)
這樣跑完\(2^0\)的點后就可以得到一個\(c\),並且一定是最優的

接下來則是技巧的問題
如果對\(c\)的每個元素單獨算,即每次都重新匹配一次,盡管我將其改為\(bfs\)並且進行了些優化,但仍然會\(T(50pts)\)

考慮一遍\(dfs\)處理所有的答案
在每個位置都先考慮異或起來為\(0\),再考慮異或起來為\(1\)的情況
然后每次將改點經過的串的個數減\(1\)
這樣就可以過了

\(\mathcal{Code}\)

50分代碼

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月16日 星期一 09時45分46秒
*******************************/
#include <cstdio>
#include <fstream>
#include <algorithm>
using namespace std;
const int len = 30;
const int maxn = 3000006;
//{{{cin
struct IO{
	template<typename T>
	IO & operator>>(T&res){
		res=0;
		bool flag=false;
		char ch;
		while((ch=getchar())>'9'||ch<'0')	flag|=ch=='-';
		while(ch>='0'&&ch<='9')	res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
		if (flag)	res=~res+1;
		return *this;
	}
}cin;
//}}}
int n,a,b,h,t,k,cnt;
int mi[len+1],res[maxn];
int q[3][maxn];//q[0] -> 哪一位 q[1] -> na q[2] -> nb
struct Trie{
	int tot=1;
	int num[maxn];
	int ch[maxn][2];
	//{{{insert
	void insert (int s)
	{
		int now=1;
		for (int i=len;i>=0;--i){
			bool to=s&mi[i];
			if (!ch[now][to]) ch[now][to]=++tot;
			now=ch[now][to];
			++num[now];
		}
	}
	//}}}
}A,B;
//{{{dfs
void dfs(int x,int y,int S,int k)
{
	if(x) --A.num[x],--B.num[y];
	if(k<0) {	res[++cnt]=S;return;}
	while(A.num[A.ch[x][0]]&&B.num[B.ch[y][0]])  dfs(A.ch[x][0],B.ch[y][0],S,k-1);
	while(A.num[A.ch[x][1]]&&B.num[B.ch[y][1]])  dfs(A.ch[x][1],B.ch[y][1],S,k-1);
	while(A.num[A.ch[x][0]]&&B.num[B.ch[y][1]])  dfs(A.ch[x][0],B.ch[y][1],S|mi[k],k-1);
	while(A.num[A.ch[x][1]]&&B.num[B.ch[y][0]])  dfs(A.ch[x][1],B.ch[y][0],S|mi[k],k-1);
}
//}}}
int main()
{
	mi[0]=1;
	for (int i=1;i<=len;++i)	mi[i]=mi[i-1]<<1;
	cin>>n;
	for (int i=1;i<=n;++i)	cin>>a,A.insert(a);
	for (int i=1;i<=n;++i)	cin>>b,B.insert(b);
	dfs(1,1,0,30);
	sort(res+1,res+n+1);
	for (int i=1;i<=n;++i)	printf("%d ",res[i]);
	return 0;
}

100分代碼

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月16日 星期一 09時45分46秒
*******************************/
#include <cstdio>
#include <fstream>
#include <algorithm>
using namespace std;
const int len = 30;
const int maxn = 3000006;
//{{{cin
struct IO{
	template<typename T>
	IO & operator>>(T&res){
		res=0;
		bool flag=false;
		char ch;
		while((ch=getchar())>'9'||ch<'0')	flag|=ch=='-';
		while(ch>='0'&&ch<='9')	res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
		if (flag)	res=~res+1;
		return *this;
	}
}cin;
//}}}
int n,a,b,h,t,k,cnt;
int mi[len+1],res[maxn];
int q[3][maxn];//q[0] -> 哪一位 q[1] -> na q[2] -> nb
struct Trie{
	int tot=1;
	int num[maxn];
	int ch[maxn][2];
	//{{{insert
	void insert (int s)
	{
		int now=1;
		for (int i=len;i>=0;--i){
			bool to=s&mi[i];
			if (!ch[now][to]) ch[now][to]=++tot;
			now=ch[now][to];
			++num[now];
		}
	}
	//}}}
}A,B;
//{{{dfs
void dfs(int x,int y,int S,int k)
{
	if(x) --A.num[x],--B.num[y];
	if(k<0) {	res[++cnt]=S;return;}
	while(A.num[A.ch[x][0]]&&B.num[B.ch[y][0]])  dfs(A.ch[x][0],B.ch[y][0],S,k-1);
	while(A.num[A.ch[x][1]]&&B.num[B.ch[y][1]])  dfs(A.ch[x][1],B.ch[y][1],S,k-1);
	while(A.num[A.ch[x][0]]&&B.num[B.ch[y][1]])  dfs(A.ch[x][0],B.ch[y][1],S|mi[k],k-1);
	while(A.num[A.ch[x][1]]&&B.num[B.ch[y][0]])  dfs(A.ch[x][1],B.ch[y][0],S|mi[k],k-1);
}
//}}}
int main()
{
	mi[0]=1;
	for (int i=1;i<=len;++i)	mi[i]=mi[i-1]<<1;
	cin>>n;
	for (int i=1;i<=n;++i)	cin>>a,A.insert(a);
	for (int i=1;i<=n;++i)	cin>>b,B.insert(b);
	dfs(1,1,0,30);
	sort(res+1,res+n+1);
	for (int i=1;i<=n;++i)	printf("%d ",res[i]);
	return 0;
}


如有哪里講得不是很明白或是有錯誤,歡迎指正
如您喜歡的話不妨點個贊收藏一下吧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM