CF1361C. Johnny and Megan‘s Necklace(构造,欧拉回路,传递闭包)

CF1361C. Johnny and Megan’s Necklace

Solution

真duliu,快做吐了。。。

刚开始想了一个假做法(但前面还是很真的)。

假的做法大概是你发现这个东西具有传递性,因此你考虑把 a i a_i ai翻转后在后面补0直到20位之后,从小到大枚举 i i i,验证答案是否为 20 − i 20-i 20i

然后把从高到低的 20 − i 20-i 20i位相同的点之间都连上边。

因为一些特殊的传递性 a    x o r    b ≥ 2 x , b    x o r    c ≥ 2 y → a    x o r    c ≥ 2 m i n ( x , y ) a\;xor\;b\geq 2^x,b\;xor\;c\geq 2^y\to a\;xor\;c\geq 2^{min(x,y)} axorb2x,bxorc2yaxorc2min(x,y)),所以我们只需要相邻连边,并查集维护,然后就可以缩点,在新图上有若干条边,要把它们都接起来。

然后就假在我以为这题性质特殊,可以直接用set模拟一遍求出方案。但实际上这是一个欧拉回路问题,我们把边连上之后有解的条件为存在包含所有边的欧拉回路,因此我们连边之后跑欧拉回路即可。

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)。(记得加当前弧优化!)。

Code

#include <bits/stdc++.h>

using namespace std;

template<typename T> inline bool upmin(T &x, T y) { return y < x ? x = y, 1 : 0; }
template<typename T> inline bool upmax(T &x, T y) { return x < y ? x = y, 1 : 0; }

#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second

typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int, int> PR;
typedef vector<int> VI; 

const lod eps = 1e-9;
const lod pi = acos(-1);
const int oo = 1 << 30;
const ll loo = 1ll << 60;
const int mods = 998244353;
const int MAXN = 2200005;
const int INF = 0x3f3f3f3f; //1061109567
/*--------------------------------------------------------------------*/

namespace FastIO{
	constexpr int SIZE = (1 << 21) + 1;
	int num = 0, f;
	char ibuf[SIZE], obuf[SIZE], que[65], *iS, *iT, *oS = obuf, *oT = obuf + SIZE - 1, c;
	#define gc() (iS == iT ? (iT = ((iS = ibuf) + fread(ibuf, 1, SIZE, stdin)), (iS == iT ? EOF : *iS ++)) : *iS ++)
	inline void flush() {
		fwrite(obuf, 1, oS - obuf, stdout);
		oS = obuf;
	}
	inline void putc(char c) {
		*oS ++ = c;
		if (oS == oT) flush();
	}
	inline void getc(char &c) {
		for (c = gc(); (c < 'a' || c > 'z') && c != EOF; c = gc());
	}
	inline void reads(char *st) {
		char c;
		int n = 0;
		getc(st[++ n]);
		for (c = gc(); c >= 'a' && c <= 'z' ; c = gc()) st[++ n] = c;
	}
	template<class I>
	inline void read(I &x) {
		for (f = 1, c = gc(); c < '0' || c > '9' ; c = gc()) if (c == '-') f = -1;
		for (x = 0; c >= '0' && c <= '9' ; c = gc()) x = (x << 3) + (x << 1) + (c & 15);
		x *= f;
	}
	template<class I>
	inline void print(I x) {
		if (x < 0) putc('-'), x = -x;
		if (!x) putc('0');
		while (x) que[++ num] = x % 10 + 48, x /= 10;
		while (num) putc(que[num --]);
	}
	struct Flusher_{~Flusher_(){flush();}} io_Flusher_;
}
using FastIO :: read;
using FastIO :: putc;
using FastIO :: reads;
using FastIO :: print;


vector<int> Ans;
int start[MAXN], a[MAXN], b[MAXN], vis[MAXN], d[MAXN], head[MAXN], id[MAXN], n, N, edgenum, Num, opt = 0;
struct enode{ int nxt, to, u, v; } e[MAXN];

void add(int u, int v, int U, int V) {
	e[++ edgenum] = (enode){head[u], v, U, V}, head[u] = edgenum;
}
void dfs(int x) {
	for (int &i = start[x]; i ; i = e[i].nxt) {
		int t = i;
		if (vis[t]) continue;
		vis[t] = vis[t ^ 1] = 1;
		dfs(e[t].to);
		if (opt) Ans.PB(e[t].v), Ans.PB(e[t].u);
		else ++ Num, ++ Num;
	}
}
int check(int t) {
	edgenum = 1;
	for (int j = 0; j < 1 << 20 ; ++ j) head[j] = d[j] = vis[j] = 0;
	for (int j = 1; j <= n ; ++ j) {
		int x = (b[j * 2 - 1] >> t), y = (b[j * 2] >> t);
        add(x, y, j * 2 - 1, j * 2);
		add(y, x, j * 2, j * 2 - 1);
		++ d[x], ++ d[y];
	}
	int flag = 0;
	for (int j = 0; j < 1 << 20 ; ++ j) flag |= (d[j] & 1), start[j] = head[j];
	if (!flag) {
		Num = (opt ? INF : 0);
		dfs(b[1] >> t);
		if (Num < N) return 0;	
		return 1;
	}
	return 0;
}
signed main() {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif
	read(n), N = n << 1;
	for (int i = 1; i <= n ; ++ i) read(a[i * 2 - 1]), read(a[i * 2]);
	for (int i = 1; i <= N ; ++ i) 
		for (int j = 0; j < 20 ; ++ j) b[i] = b[i] << 1 | (a[i] & 1), a[i] >>= 1;
	int l = 0, r = 20;
	while (l < r) {
		int mid = (l + r) >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}
	opt = 1, check(r);
	print(20 - r), putc('\n');
	for (auto v : Ans) print(v), putc(' ');
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值