CF647C Johnny Necklace(歐拉回路)

題意

nn 個二元組 (ai,bi)(a_i,b_i),二元組可以翻轉。現在要將這些二元組接成一個環。連接部分的漂亮度是 lowbitx xor ylowbit_{x~xor~y}x=yx=y 時漂亮度爲 2020)。環的漂亮度爲連接部分的最小漂亮度,現在要最大化漂亮度,並輸出連接順序。(第 ii 個二元組的編號爲 2i12i-12i2i
其中 ai,bi<220n500000a_i,b_i< 2^{20},n\leq 500000

分析

先考慮答案大於等於 ll 時的性質:
也就是任意一個連接處,x xor yx ~ xor~yll 的倍數。
因此答案具有單調性。
考慮怎麼檢驗答案。
xxyy 能作爲連接處,意味着 x xor yx~xor~y 在模 2l2^l 意義下相同,也就是 xy (mod 2l)x\equiv y~(mod~2^l)
那麼,能否連成一個環,其實等價於是否存在歐拉回路(這個可能需要思考一下)。判斷歐拉回路存不存在很好判斷。
然後找到答案之後再求一邊歐拉回路就可以了。
複雜度 O(Vlog20+nlog20)O(V\log20 + n\log 20)

代碼如下

#include <bits/stdc++.h>
using namespace std;

int read(){
	int x, f = 1;
	char ch;
	while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
	x = ch - '0';
	while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
	return x * f;
}

const int N = 2000005;
int n, A[N], B[N], ans[N], m, h[N], f[N], du[N], vis[N * 2], cnt = 1;

struct node{
	int a, b, x, y, n;
}d[N * 2];

void cr(int a, int b, int x, int y){
	d[++cnt].a = a; d[cnt].b = b; d[cnt].x = x; d[cnt].y = y; d[cnt].n = h[a]; h[a] = cnt;
}

int find(int x){
	return x == f[x]? x: f[x] = find(f[x]);
}

int chk(int x){
	int i, j, a, b, tot = 0;
	for(i = 0; i <= (1 << 20); i++) du[i] = 0, f[i] = i;
	for(i = 1; i <= n; i++){
		a = A[i] & x; b = B[i] & x;
		du[a]++; du[b]++;
		if(find(a) != find(b)) f[f[b]] = f[a];
	}
	for(i = 0; i <= (1 << 20); i++){
		if(!du[i]) continue;
		if(du[i] % 2) return 0;
		if(find(i) == i) tot++;
	}
	return tot == 1;
}

void dfs(int a, int id){
	for(int &i = h[a]; i; i = d[i].n){//此處不加引用會使複雜度高達 n^2,加了引用類似於網絡流中的當前弧優化,也就是實時改變 h 指針 
		if(vis[i]) continue;
		vis[i] = vis[i ^ 1] = 1;
		int b = d[i].b;
		dfs(b, i);
	}
	ans[++m] = id;
}

void work(int x){
	int i, j, a, b;
	for(i = 1; i <= n; i++){
		a = A[i] & x; b = B[i] & x;
		cr(a, b, 2 * i - 1, 2 * i);
		cr(b, a, 2 * i, 2 * i - 1);
	}
	dfs(a, 1);
}

int main(){
	int i, j, k, a, b, l = 0, r = 20;
	n = read();
	for(i = 1; i <= n; i++) A[i] = read(), B[i] = read();
	while(l < r){
		int mid = l + r + 1 >> 1;
		if(chk((1 << mid) - 1)) l = mid;
		else r = mid - 1;
	}
	printf("%d\n", l);
	work((1 << l) - 1);
	for(i = m - 1; i >= 1; i--){
		j = ans[i];
		printf("%d %d ", d[j].x, d[j].y);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章