并查集 ---- 扩展域并查集判二分图 + 循环模拟字典树 The 2020 ICPC Asia Macau Regional Contest C. Club Assignment (详解)

news/2024/7/7 19:35:18

题目链接


题目大意:

有n个数,现在要把他们拆分成两个集合,假设S为集合,有如下定义:
f(S)={min(x⊕y)∣x,y∈S,andx!=y}f(S)=\{min(x\oplus y)|x,y\in S,and\;x!=y\}f(S)={min(xy)x,yS,andx!=y}

将n个数拆分为两个集合A,B,要求最大化min(f(A),f(B))m i n ( f ( A ) , f ( B ) )min(f(A),f(B)),并输出划分集合的方案,如果有多种,则输出任意一个.


解题思路:

题解思路:
首先要最大化minminmin,那么我们先转换成图论问题:异或完全图
就是每个nnn点,第iii个点和第jjj个点之间边权是ai⊕aja_i\oplus a_jaiaj,

那么我们要使用我们先按照边权从小到大看:就是不断把点加入集合,就是对于边权最小的这两个点,肯定不能在一个集合里面,然后把这条边加入集合,相当于这两个点要在不同的集合,那么我们一直往这个图里面加边,一旦这个图出现了奇环那么这条边连的两个点一定要在一个集合里面了!!那么这条边就是答案。

出现奇环意味着这个图不是二分图。那么就是不断往里面加边,然后,如果这个边一加进去就不是二分图了,那么这条边权就是答案了。其他边怎么连都会不会比这个边更小。

但是边有n2n^2n2条,我们不可能暴力去找异或最小的两条边,肯定不行,那么我们该怎么优化?

因为我们要异或最小嘛,那么我们先看看高位,高位相同的在一组,因为这两个高位不同的数在一个集合里面肯定不一定是最小的。还有关键如果当前位分组如果数的个数大过2,那么无论你怎么分这一位在最终答案都是0。

eg:我们先按照第31位划分两个集合,因为这两个集合里面点互相连边,肯定比跨集合连边结果还要小,那么我们就是尽可能去让这两个集合里面的点被划分到1,2里面。但是可能两个集合里面的点数超过3,那么根据鸽巢原理肯定有两个点一定要被分到一个集合里面那么这第31位就结果肯定是0了。那么我们接着对这个集合里面的点按照高30位划分(这是在31位划分好的集合上再划分)。一直划分到第iii位的时候,这时候数全部被划分成xxx个集合,每个集合大小都≤2\leq22,那么说明同一个集合里面的点可以被划分到不同答案组里面(1or2)(1\;\text{or}\;2)(1or2),那么这一位就可以⊕=1\oplus=1=1
但是不是这样就结束了呢?肯定不是我们还要接着看[i−1,0][i-1,0][i1,0]这些位置的贡献,在这之前我要把第iii位的贡献删掉,毕竟iii位已经比下面限死了。依次类推就结束了

那么上面按照高位分组是不是很像trie树,按照高位分,不存在大过2的分组就是看trie树下面叶子节点的个数是否大过2?

在这里插入图片描述

在这里插入图片描述
在划分好集合后,并不是两个点一定是在不同的集合里面了,根据上面的原理,这个图一定要是二分图。
动态判二分图那就是扩展域并查集了。


AC code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {read(first);read(args...);
}int T, n;
int arr[maxn], col[maxn];
struct dsu {int fa[maxn << 1];inline void init(int n) {for(int i = 1; i <= n; ++ i) fa[i] = i;}inline int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}inline void merge(int x, int y, int n) {int fx = find(x);int fxn = find(x + n);int fy = find(y);int fyn = find(y + n);fa[fx] = fyn;fa[fxn] = fy;}
}dsu;
int main() {IOS;cin >> T;while(T --) {cin >> n;dsu.init(n<<1|1);for(int i = 1; i <= n; ++ i) col[i] = col[i + n] = 0;for(int i = 1; i <= n; ++ i) cin >> arr[i];ll minans = 0;for(int i = 29, nouse = 0; i >= 0; -- i) {nouse |= 1<<i;unordered_map<int,vector<int>> Set;for(int j = 1; j <= n; ++ j) Set[arr[j] & nouse].push_back(j);bool flag = 0;for(auto it : Set) {if((int)it.second.size() > 2 || ((int)it.second.size() == 2 && dsu.find(it.second[0]) == dsu.find(it.second[1]))) flag = 1;//判断当前位划分是否合法}if(flag == 1) continue;for(auto it : Set)if((int)it.second.size() == 2)dsu.merge(it.second[0],it.second[1],n);minans |= 1<<i;nouse ^= 1<<i; // 把当前位的贡献删掉相当于接着找生成树里面的边}cout << minans << endl;for(int i = 1; i <= n; ++ i) {if(col[dsu.find(i)]) cout << col[dsu.find(i)]; // 模拟二分图染色过程else if(col[dsu.find(i+n)]) cout << (col[dsu.find(i)] = 3 - col[dsu.find(i+n)]);else cout << (col[dsu.find(i)] = 1); }cout << endl;}return 0;
}

http://lihuaxi.xjx100.cn/news/285909.html

相关文章

实现Date函数属性中的format方法

js中没有Date.format方法的&#xff0c;所以在date属性中加format方法 //js格式化属性 Date.prototype.format function (format) {   var o {     "M": this.getMonth() 1, //month     "d": this.getDate(), //day     "h": …

网易开源支持图像识别的自动化UI测试工具,零基础亲测好评!

编辑 | Jane出品 | AI科技大本营AI科技大本营给大家推荐了很多有意思、适合开发者们的工具&#xff0c;比如代码修复神器、帮小白快速分析 Error、PDF 翻译工具、变量命名神器等等。今天&#xff0c;营长要专门给测试人员&#xff0c;或者想做测试的小伙伴们推荐一款工具&#…

[CQOI2009]中位数图 详细题解

题目链接&#xff1a; https://ac.nowcoder.com/acm/problem/19913 题目描述&#xff1a; 给出1~n的一个排列&#xff0c;统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后&#xff0c;位于中间的数。 题解&#xff1a; 因为中位数是…

容斥 + 爆搜打表 ---- 2020年南京icpc H.Harmonious Rectangle

题目链接 题目大意&#xff1a; 就是给你一个二维平面{(x,y)∣1≤x≤n,1≤y≤m}\{(x,y)|1\leq x\leq n,1\leq y \leq m\}{(x,y)∣1≤x≤n,1≤y≤m},你现在有3种颜色&#xff0c;你可以给写平面的点涂上颜色&#xff0c;问你至少存在4个点(x1,y1),(x2,y2),(x1,y2),(x2,y1)(x1,y…

坑爹的Python陷阱(避坑指南)

点击上方“视学算法”&#xff0c;星标公众号重磅干货&#xff0c;第一时间送达作者&#xff1a;xybaby来源&#xff1a;http://www.cnblogs.com/xybaby/我个人对陷阱的定义是这样的&#xff1a;代码看起来可以工作&#xff0c;但不是以你“想当然“”的方式。如果一段代码直接…

程序员单身比例有多高?【2019开发者图鉴】告诉你

编辑 | Jane 出品 | AI科技大本营 本次调查共 8 个问题&#xff0c;根据这些数字我们整理了《2019开发者图鉴》&#xff0c;下面营长将发现的一些有意思的数字分享给大家&#xff1a; 性别与年龄 本次参与调查的男女比例约为 8&#xff1a;2&#xff08;男8女2&#xff09;。 …

基于plc的自动洗碗机的设计(西门子)

目 录 摘 要 I Abstract II 1绪论 1 1.1全自动洗碗机的发展 1 1.2全自动洗碗机概述 2 1.2.1 全自动洗碗机的分类 2 1.2.2 全自动洗碗机的基本结构 3 1.2.3 全自动洗碗机的工作原理 4 1.3研究主要内容 4 2 全自动洗碗机机械设计 6 2.1 整体方案设计 6 2.2 各重要部件设计 6 2.2.…

NC14414 小AA的数列

题解&#xff1a;求一个序列问长度为偶数且在[L, R]范围内的异或和的和&#xff0c;这个题考察的异或和的问题&#xff0c;因为异或和的话就要牵扯到二进制&#xff0c;所以一般来说这类问题就是将其拆开来进行计算。 首先&#xff1a;异或计算 1xor10&#xff0c;0xor00&…