CodeForces - 923 C. Perfect Security
- 题意:More precisely, for given A and P, find the lexicographically smallest message O, for which there exists a permutation π such that O(i) ^ π(P(i)) == A(i) for every i.
- 翻译:A数组顺序不变,P数组顺序可变。找到一个数组P的排列,使得对应位的Ai ^ Pi得到一个新的的序列,这个序列是所有可能可以得到的所有序列中的字典序最小的那一个。
思路
就很显然的是01字典树咯~因为要找字典序最小的一个,所以我们采取贪心的策略。
对P数组建立字典树,然后查询与A[ i ]异或最小的数P[ k ],最重要的是不要忘记删除P[ k ],因为已经匹配过了嘛!【注意A[ i ]遍历要[0, n),因为贪心的嘛!保证遍历过的每一个都是当前异或最小~】所以就不能再和其他匹配了。毕竟中国都是一夫一妻制(滑稽脸)~
AC CODE
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 300000 * 30 * 2 + 7;
inline int read()
{
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
int n;
int a[maxN], p[maxN];
int tire[maxN][2], tot, val[maxN], cnt[maxN];
void Clear(int rt)
{
for(int i = 0; i < 2; i ++ ) tire[rt][i] = 0;
}
void Insert(int num)
{
int rt = 0;
for(int i = 29; i >= 0; i -- )
{
int id = num >> i & 1;
if(!tire[rt][id]) {tire[rt][id] = ++ tot; Clear(tot); }
++ cnt[tire[rt][id]];
rt = tire[rt][id];
}
val[rt] = num;
}
void Delete(int num)
{
int rt = 0;
for(int i = 29; i >= 0; i -- )
{
int id = num >> i & 1;
-- cnt[tire[rt][id]];
rt = tire[rt][id];
}
}
int Search(int num)//找到异或最小。那就找尽可能相同的咯~
{
int rt = 0;
for(int i = 29; i >= 0; i -- )
{
int id = num >> i & 1;
if(tire[rt][id] && cnt[tire[rt][id]]) rt = tire[rt][id];
else rt = tire[rt][id ^ 1];
}
return val[rt];
}
int main()
{
Clear(0); tot = 0;
n = read();
for(int i = 0; i < n; i ++ )
a[i] = read();
for(int i = 0; i < n; i ++ )
{
p[i] = read();
Insert(p[i]);
}
for(int i = 0; i < n; i ++ )
{
int ans = Search(a[i]);
Delete(ans);
printf("%d ", ans ^ a[i]);
}
printf("\n");
return 0;
}