【CodeForces】947 C. Perfect Security 异或Trie

【题目】C. Perfect Security

【题意】给定长度为n的非负整数数组A和数组B,要求将数组B重排列使得A[i]^B[i]的字典序最小。n<=3*10^5,time=3.5s。

【算法】异或Trie

【题解】对一个数组O(n log n)建立异或Trie,就能O(log n)判断任意一个数在这个数组中异或值最大的数

所以对B建异或Trie(每个数字从高二进制位开始插入),然后数组A依次在Trie上跑,从上到下尽量跑向相同数字边,这样得到字典序最小,路径中顺便删除标记。

复杂度O(n log n)。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#define ll long long
#define lowbit(x) x&-x
using namespace std;
int read(){
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c==‘-‘)t=-1;
    do{s=s*10+c-‘0‘;}while(isdigit(c=getchar()));
    return s*t;
}
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a<b?b:a;}
int ab(int x){return x>0?x:-x;}
//int MO(int x){return x>=MOD?x-MOD:x;}
//void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
/*------------------------------------------------------------*/
const int inf=0x3f3f3f3f,maxn=300010;
int ch[maxn*30][2],sz,num[maxn*30*2],a[maxn];

int n;
void insert(int y){
    int x=0;
    for(int i=29;i>=0;i--){
        bool k=(y&(1<<i))>0;
        if(!ch[x][k])ch[x][k]=++sz;
        num[ch[x][k]]++;
        x=ch[x][k];
    }
}
int find(int y){
    int x=0;
    for(int i=29;i>=0;i--){
        bool k=(y&(1<<i))>0;
        if(num[ch[x][k]]>0){
            x=ch[x][k];
            num[x]--;
            y^=((k)<<i);
        }
        else{
            x=ch[x][!k];
            num[x]--;
            y^=((!k)<<i);
        }
    }
    return y;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)insert(read());
    for(int i=1;i<=n;i++)printf("%d ",find(a[i]));
    return 0;
}

原文地址:https://www.cnblogs.com/onioncyc/p/8545459.html

时间: 2024-08-29 20:50:54

【CodeForces】947 C. Perfect Security 异或Trie的相关文章

Codeforces 948D Perfect Security(字典树)

题目链接:Perfect Security 题意:给出N个数代表密码,再给出N个数代表key.现在要将key组排序,使key组和密码组的亦或所形成的组字典序最小. 题解:要使密码组里面每个数都找到能使其亦或和最小的数可以将key建成一棵字典树(这里建树方式很关键,可以每个数都从2^31开始建树,这样可以使我们在遍历树查询更加方便).之后再遍历密码组每次在字典树里面找到一个能使它亦或和最小的数,再将这个数从字典树中删掉...  字典树太久不写,很多东西都忘记了! 1 #include<bits/s

01Trie树 CF923C Perfect Security

CF923C Perfect Security 上下各n个数,求一种排列p,使上面的数i异或pi成为新的数i,求方案另字典序最小,输出该结果 01Trie树. 记录每个节点经过多少次. 每一次查询的时候将经过的点的标记加1. 那么当我们要去走某一个节点的时候,就去判断他的标记是否小于初始的值,如果不是那么就不能走. 教训告诉我们一定要想好细节再打代码,我没想好怎么处理初始标记就去写了个拓扑排序.低智低智... code: #include <iostream> #include <cst

CF 979D Kuro and GCD and XOR and SUM(异或 Trie)

CF 979D Kuro and GCD and XOR and SUM(异或 Trie) 给出q(<=1e5)个操作.操作分两种,一种是插入一个数u(<=1e5),另一种是给出三个数x,k,s(<=1e5),求当前所有数中满足,k|v,x+v<=s,且\(x\oplus v\)最大的v. 做法好神啊.关于异或的问题有一种常见做法,就是利用01trie来查找在一堆数里面,那个数与x的异或值最大.这道题就是这个思路.如果去掉k必须整除v这个条件,那么就转化成了上一个问题(只不过有最大

codeforces 794F Leha and security system

目录 codeforces 794F Leha and security system 题意 题解 Code codeforces 794F Leha and security system 题目传送门 题意 给出一个长度为\(n\)的序列,有两种操作: 1.将区间\([l,r]\)中每一个元素的数字\(x\)改为\(y\). 2.询问区间\([l,r]\)的元素之和. 一共\(q\)次操作.\((1 \leq n,q \leq 10^5)\) 题解 看起来就很可做的题目,实际上只是线段树的应用

Codeforces Round #626 D. Present 异或按位确定 +二分or双指针

Codeforces Round #626 D. Present 异或按位确定 +二分or双指针 题意 给n个数,求他们两两的和的异或结果 n(4e5) 值域(1e7) 思路 异或问题一般都是按位确定,那么怎么确定第k位的值呢.首先第k位的值只和[1,k]位有关系,也就是说只跟a[i]本来在这一位有的数和进位有关系.那么怎么处理和的问题呢.首先我们只考虑[1..k]位,那么他们的和记为sum,如果sum在第k位有值 那么sum的值为 \(2^k+x\)因为只考虑[1..k]位所以a的最大值为\(

BZOJ 3689 异或 Trie木+堆

标题效果:特定n的数量,这种需求n数22 XOR的值前者k少 首先,我们建立了一个二进制的所有数字Trie木,您可以使用Trie木size域检查出一些其他的数字XOR值首先k少 然后,我们要保持一个堆.其他XOR的整数值首先2增加堆(第一小是自己异或自己.不在题目要求范围内).当取出一个数异或值的第k小后,将第k+1小增加堆 一个异或值会被两个数分别取出一次.所以取出奇数次时输出,取2*k次就可以 时间复杂度O(nlogn) #include<cstdio> #include<cstri

Educational Codeforces Round 23 E. Choosing The Commander (trie)

题目链接: Educational Codeforces Round 23 E. Choosing The Commander 题意: 一共有n个操作. 1.  插入一个数p 2.  删除一个数p 3.  询问有多少个数 使得 x^p<l 题解: 对于前两种操作用01trie就能解决. 对于对三个操作,我们考虑在trie上搜索. 1.  当l的bit位是1时,那边bit位是p的字数全部的数都会小于l,(因为p^p=0) 2.  当l的bit为是0时,那边只能向bit位是p的子树中搜. 这样算下来

XJOI 异或 (Trie树)

这题对我来说真是一块大蛋糕,又是一座大山 大蛋糕是因为算法很好胡 大山是因为我实在是太菜 然后我就在考场上续了两个小时 /-------------------------------------------/ 这题算法不算难想,但对我来说挺难打 1.将ai拆成二进制,由高位到低位加入Trie树,不足的补前导0,每个节点的ans统计子树中有多少个值 2.读入区间l,r拆成区间1-r+1,1-l处理 3.search时统计小于limit的数量 4.如果pos的一个子树内异或x最大值之差小于limi

Codeforces 633C Spy Syndrome 2(DP+Trie树)

题目大概说给一个加密的字符串,加密规则是把原文转化成小写字母,然后各个单词反转,最后去掉空格.现在给几个已知的单词,还原加密的字符串. 和UVa1401一个道理.. 用dp[i]表示加密字符前i个字符都被解密时,最后所用单词编号,为0表示不能被解密 然后转移一个样,从i出发往前在Trie树上跑,看看能否找到不为0的dp[j],而str[j+1]str[j+2]...str[i-1]str[i]是单词 最后输出方案就根据dp里面的值从最后面回溯找到并输出即可 时间复杂度O(加密字符串长*单词最大长