CF923C Perfect Security

一、题目

点此看题

题目描述

给你两个长度为 n n 的数组 a , b a,b ,你可以把 b b 数组任意排列后对应位和 a a 数组异或,求字典序最小的异或结果。

二、解法

很容易看出的贪心,枚举 a a 中的每一个值,找到和 b b 未选中的值异或最小的结果,按顺序输出即可。

可以用一个数据结构维护 b b 数组,异或相关问题我们可以使用 t r i e trie 树,我们把 b b 数组拿去建 t r i e trie 树,然后把 a a 中的每个值拿去匹配, t r i e trie 树上的每个点维护一个子树中还未被选中个数,就很容易做了。

注意把每一个值拆成长度为 30 30 的二进制串,从高位到低位做即可,时间复杂度 O ( n log n ) O(n\log n)

#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 300005;
const int M = 30*N;
int read()
{
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
}
int n,a[M],b[31];
struct trie
{
    int cnt,ch[M][2],val[M];
    trie() {cnt=1;}
    void add(int x)
    {
        int p=1;
        for(int i=30;i>=0;i--)
        {
            int c=(x>>i)&1;
            if(!ch[p][c]) ch[p][c]=++cnt;
            p=ch[p][c];val[p]++;
        }
    }
    void solve(int x)
    {
        int p=1,ans=0;
        for(int i=30;i>=0;i--)
        {
            int c=(x>>i)&1;
            if(!val[ch[p][c]]) c^=1;
            p=ch[p][c];val[p]--;
            ans=(ans<<1)+c;
        }
        printf("%d ",ans^x);
    }
}tr;
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=1;i<=n;i++)
        tr.add(read());
    for(int i=1;i<=n;i++)
        tr.solve(a[i]);
}
发布了257 篇原创文章 · 获赞 13 · 访问量 6728

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/104172252