HDU 6625 three arrays 求两个序列异或最小值的排列(一个可以推广的正解
@
题意:
\(T(100)\)组,每组两个长度为\(n(100000)\)的排列,你可以将\(a[]\)和\(b[]\)随机排列,可以得到\(c[i]=a[i]\)^\(b[i]\),求字典序最小的\(c[]\)。
解析
一个显然对的贪心做法:
针对本题
- 每次两颗字典树同时往下走,如果都有\(0\)或者\(1\)这条路径,就随便同时走\(0\;or\;1\)这条路径,否则只能一个走\(0\),一个走\(1\)。这样复杂度是严格\(O(log)\)的,最后将得到的\(n\)个数字排序即为最后答案。
- 这样为什么正确呢?
- 如果当前两字典树都有\(0\)和\(1\)的路径,同时走\(0\)这条路得到数字肯定不能保证是当前能异或出来的最小值,但是可以肯定的是他一定是字典序最小的序列所包含的某个值。
- 如果想单纯的求两个01字典树异或最小值,个人感觉还没有较好的复杂度的做法。
一个可以推广的正解:
- 出题人\(dreamoon\)提供的正解:
- 现在\(a[]\)中随便找一个数字\(x\),然后在\(b[]\)中相应找一个和\(x\)匹配异或最小的数字\(y\),再在\(a[]\)里面找一个和\(y\)匹配最小的数字\(z\),递归下去一定会找到一个大小为2的环。
- 把这个环这两个数字取出来,再回到上一个失配位置继续递归下去。
- 这样得到的\(n\)个数字排序后即为最终答案。
- 复杂度同样很科学并且这个思路适用性很广。
Code1
const int MXN = 1e5 + 7;
const int MXE = 2e6 + 7;
int n, m;
int ar[MXN], br[MXN];
struct Trie {
int tot;
int nex[MXE][2], num[MXE], val[MXE];
Trie(){nex[0][0] = nex[0][1] = -1;}
void newnode() {
++ tot;
nex[tot][0] = nex[tot][1] = -1;
}
void inisert(int x) {
int rt = 0;
for(int i = 31, tmp; i >= 0; --i) {
tmp = ((x>>i)&1);
if(nex[rt][tmp] == -1) newnode(), nex[rt][tmp] = tot;
rt = nex[rt][tmp];
num[rt] ++;
}
val[rt] = x;
}
void del(int x) {
int rt = 0;
for(int i = 31, tmp; i >= 0; --i) {
tmp = ((x>>i)&1);
int lst = rt;
rt = nex[rt][tmp];
nex[lst][tmp] = -1;
num[rt] = 0;
}
}
}cw[2];
bool check(int id, int rt, int tmp) {
return cw[id].nex[rt][tmp] != -1 && cw[id].num[cw[id].nex[rt][tmp]] > 0;
}
int getans() {
int rt1 = 0, rt2 = 0;
for(int i = 31; i >= 0; --i) {
if(check(0, rt1, 0) && check(1, rt2, 0)) {
rt1 = cw[0].nex[rt1][0];
rt2 = cw[1].nex[rt2][0];
-- cw[0].num[rt1];
-- cw[1].num[rt2];
}else if(check(0, rt1, 1) && check(1, rt2, 1)) {
rt1 = cw[0].nex[rt1][1];
rt2 = cw[1].nex[rt2][1];
-- cw[0].num[rt1];
-- cw[1].num[rt2];
}else if(check(0, rt1, 1) && check(1, rt2, 0)) {
rt1 = cw[0].nex[rt1][1];
rt2 = cw[1].nex[rt2][0];
-- cw[0].num[rt1];
-- cw[1].num[rt2];
}else if(check(0, rt1, 0) && check(1, rt2, 1)) {
rt1 = cw[0].nex[rt1][0];
rt2 = cw[1].nex[rt2][1];
-- cw[0].num[rt1];
-- cw[1].num[rt2];
}
}
return cw[0].val[rt1] ^ cw[1].val[rt2];
}
int main() {
#ifndef ONLINE_JUDGE
freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
// freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
int tim = read();
while(tim --) {
n = read();
cw[0].tot = cw[1].tot = 0;
for(int i = 1; i <= n; ++i) ar[i] = read(), cw[0].inisert(ar[i]);
for(int i = 1; i <= n; ++i) br[i] = read(), cw[1].inisert(br[i]);
vector<int> vs;
for(int i = 1; i <= n; ++i) vs.eb(getans());
sort(all(vs));
for(int i = 0; i < SZ(vs); ++i) printf("%d%c", vs[i], " \n"[i == SZ(vs) - 1]);
for(int i = 1; i <= n; ++i) cw[0].del(ar[i]), cw[1].del(br[i]);
}
return 0;
}
Code2
const int MXN = 1e5 + 7;
const int MXE = 2e6 + 7;
int n, m;
int ar[MXN], br[MXN];
struct Trie {
int tot;
int nex[MXE][2], num[MXE], val[MXE];
Trie(){nex[0][0] = nex[0][1] = -1;}
void newnode() {
++ tot;
nex[tot][0] = nex[tot][1] = -1;
}
void inisert(int x) {
int rt = 0;
for(int i = 30, tmp; i >= 0; --i) {
tmp = ((x>>i)&1);
if(nex[rt][tmp] == -1) newnode(), nex[rt][tmp] = tot;
rt = nex[rt][tmp];
num[rt] ++;
}
val[rt] = x;
}
int query(int x) {
int rt = 0;
for(int i = 30, tmp; i >= 0; --i) {
tmp = ((x>>i)&1);
if(nex[rt][tmp] != -1 && num[nex[rt][tmp]]) rt = nex[rt][tmp];
else rt = nex[rt][!tmp];
}
return val[rt];
}
int find() {
int rt = 0;
for(int i = 30, tmp; i >= 0; --i) {
if(nex[rt][0] != -1 && num[nex[rt][0]]) rt = nex[rt][0];
else if(nex[rt][1] != -1 && num[nex[rt][1]]) rt = nex[rt][1];
}
if(rt == 0) return -1;
return val[rt];
}
void del() {
for(int i = 0; i <= tot + 1; ++i) num[i] = 0, clr(nex[i], -1);
tot = 0;
}
void sub(int x) {
int rt = 0;
for(int i = 30, tmp; i >= 0; --i) {
tmp = ((x>>i)&1);
rt = nex[rt][tmp];
num[rt] --;
}
}
}cw[2];
/*
* 这种做法不能保证每次求出来的异或最小值都是单调递增的,但是将n次得到的值排序后一定是正确答案
* 如果想单纯的求两个01字典树异或最小值,个人感觉还没有较好的复杂度的做法。
* 关于本题,还有一个出题人提供适用性更加广泛的正解:
* 现在a中随便找一个数字,然后在b中找一个和他匹配最小的数字,再在a里面找一个和上个数匹配最小的数字,递归下去一定会找到一个大小为2的环
* 把这个环取出来,在回到上一个位置继续递归下去。得到的n个数字排序即为最终答案。
* */
vector<int> vs;
int dfs(int id, int x, int lst) {
int tmp = cw[!id].query(x);
if(tmp == lst) {
vs.eb(tmp ^ x);
cw[id].sub(x);
cw[!id].sub(tmp);
return id;
}
int ret = dfs(!id, tmp, x);
if(ret != id) return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
// freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
int tim = read();
while(tim --) {
n = read();
for(int i = 1; i <= n; ++i) ar[i] = read(), cw[0].inisert(ar[i]);
for(int i = 1; i <= n; ++i) br[i] = read(), cw[1].inisert(br[i]);
vs.clear();
while(1) {
int tmp = cw[0].find();
if(tmp == -1) break;
dfs(1, tmp, -1);
}
sort(all(vs));
for(int i = 0; i < SZ(vs); ++i) printf("%d%c", vs[i], " \n"[i == SZ(vs) - 1]);
cw[0].del(), cw[1].del();
}
return 0;
}
原题描述

字典树动态求Mex
CF842D
把所有数字从高位开始插入字典树,对每个节点维护下面叶子节点的个数。判断与当前询问为异或为0的子树是否满叶子,若不是满叶子则Mex在此路径下,反之在异或为1那条路径下。
const int TRIE_MAX = 25;
int n, m;
int ar[MXN];
int node, nex[MXN][2], is[MXN];
void new_node() {
clr(nex[++node], -1);
}
void insert(int x) {
int rt = 0;
for(int i = TRIE_MAX, t; i >= 0; --i) {
t = (x>>i)&1;
if(nex[rt][t] == -1) {
new_node();
nex[rt][t] = node;
}
rt = nex[rt][t];
}
if(is[rt] == 0) {
rt = 0;
for(int i = TRIE_MAX, t; i >= 0; --i) {
t = (x>>i)&1;
rt = nex[rt][t];
++ is[rt];
}
}
}
int query(int x) {
int ans = 0, rt = 0;
for(int i = TRIE_MAX, t; i >= 0; --i) {
t = (x>>i)&1;
if(rt == -1 || nex[rt][t] == -1) break;
// if(i <= 1) debug(rt, t, nex[rt][t], is[nex[rt][t]], i)
if(is[nex[rt][t]] == (1<<i)) t ^= 1, ans |= (1<<i);
rt = nex[rt][t];
// debug(rt)
}
return ans;
}
HDU 6625 three arrays 求两个序列异或最小值的排列(一个可以推广的正解的更多相关文章
- 【总结】matlab求两个序列的相关性
首先说说自相关和互相关的概念. 自相关 在统计学中的定义,自相关函数就是将一个有序的随机变量系列与其自身作比较.每个不存在相位差的系列,都与其都与其自身相似,即在此情况下,自相关函数值最大. 在信号 ...
- Median of Two Sorted Arrays (找两个序列的中位数,O(log (m+n))限制) 【面试算法leetcode】
题目: There are two sorted arrays A and B of size m and n respectively. Find the median of the two sor ...
- HDU 1171 Big Event in HDU【01背包/求两堆数分别求和以后的差最小】
Big Event in HDU Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) T ...
- LeetCode:4_Median of Two Sorted Arrays | 求两个排序数组的中位数 | Hard
题目: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the ...
- hdu 1950 Bridging signals 求最长子序列 ( 二分模板 )
Bridging signals Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- PTA题---求两个有序序列中位数所体现的思想。
---恢复内容开始--- 近日,在做PTA题目时,遇到了一个这样的题,困扰了很久.题目如下:已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数.有序序列A0,A1, ...
- 51nod1126 求递推序列的第N项
求递推序列的第N项 有一个序列是这样定义的:f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7. 给出A,B和N,求f(n)的 ...
- 有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列。对于1<=i,j<=k,求k个最小的(ai+bj)。要求算法尽量高效。
有两个序列A和B,A=(a1,a2,...,ak),B=(b1,b2,...,bk),A和B都按升序排列.对于1<=i,j<=k,求k个最小的(ai+bj).要求算法尽量高效. int * ...
- PAT甲题题解-1029. Median (25)-求两序列的中位数,题目更新了之后不水了
这个是原先AC的代码,但是目前最后一个样例会超内存,也就是开不了两个数组来保存两个序列了,意味着我们只能开一个数组来存,这就需要利用到两个数组都有序的性质了. #include <iostrea ...
随机推荐
- PPT技巧
1.秋叶个人的PPT三分钟教程 http://www.pptfans.cn/315656.html 2.<说服力-让你的PPT会说话>秋叶 3.<三体> https://w ...
- POI 讀取EXCEL
/*** 獲取單元格數值* * @param cell* @return*/private String getCellValue(Cell cell) {String cellValue = &qu ...
- 抓包工具fiddler下载配置(三):手机设置代理
前言 本篇仅讲解了手机端如何设置代理,是[抓包工具fiddler下载配置(一):下载/安装&信任证书]的后续文章,未下载安装抓包工具的需先参考文章[抓包工具fiddler下载配置(一):下 ...
- js中Object.defineProperty()方法的解释
菜菜: “老大,那个, Object.defineProperty 是什么鬼?” 假设我们有个对象 user ; 我们要给它增加一个属性 name , 我们会这么做 1 2 3 var user = ...
- ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
https://blog.csdn.net/ztf312/article/details/50708302 报错原因: Numpy对逻辑表达式判别不清楚,它可以返回False如果等号两边两个式子是数值 ...
- Python之计算当前月份的日期范围(calendar、datetime)
在当前月份中循环每一天大致的思路就是先计算出当月的第一天和下个月的第一天日期,还有当月总共有多少天,然后把第一天日期按照月总天数累加到下个月的第一天,就ok 啦 from datetime impor ...
- kubernetes容器集群部署Flannel网络
Overlay Network:覆盖网络,在基础网络上叠加的一种虚拟网络技术模式,该网络中的主机通过虚拟链路连接起来. VXLAN:将源数据包封装到UDP中,并使用基础网络的IP/MAC作为外层报文头 ...
- Java8 Stream流API常用操作
Java版本现在已经发布到JDK13了,目前公司还是用的JDK8,还是有必要了解一些JDK8的新特性的,例如优雅判空的Optional类,操作集合的Stream流,函数式编程等等;这里就按操作例举一些 ...
- windows7下搭建robot framework环境
第一步 安装python并设置环境变量 1.安装python: python下载地址https://www.python.org/,建议用2.7.x版本 2.设置环境变量: 方法如下所示 第二步 安 ...
- html使用字符串拼接js函数时传字符串参数
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...