【AtCoder】AtCoder Grand Contest 035 题解

【比赛链接】

【题解链接】

【A】 XOR Circle

【思路要点】

  • 题目给出的要求等价于相邻的三个数异或和为 0 0 0
  • 特判全部 a i a_i ai 均为 0 0 0 的情况,这种情况是有解的。
  • 否则,如果确定 1 , 2 1,2 1,2 号位置为 a , b a,b a,b ,则 3 3 3 号位置一定为 a ⊕ b a\oplus b ab 4 4 4 号位置一定为 a a a ,以此类推。
  • 因此剩余情况下,有解的充要条件是 N N N 3 3 3 的倍数, a i a_i ai 共有 3 3 3 类,每一类共有 N 3 \frac{N}{3} 3N 个(两类 a i a_i ai 可以相同),且三类 a i a_i ai 的异或和为 0 0 0
  • 时间复杂度 O ( N L o g N ) O(NLogN) O(NLogN)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {
    x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {
    x = min(x, y); } 
template <typename T> void read(T &x) {
    
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
    
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
    
	write(x);
	puts("");
}
int n, cnt, a[MAXN];
int main() {
    
	read(n), cnt = 0;
	for (int i = 1; i <= n; i++)
		read(a[i]), cnt += a[i] != 0;
	if (cnt == 0) {
    
		puts("Yes");
		return 0;
	}
	if (n % 3) {
    
		puts("No");
		return 0;
	}
	sort(a + 1, a + n + 1);
	if ((a[n / 3] ^ a[n / 3 * 2] ^ a[n]) == 0 && a[1] == a[n / 3] && a[n / 3 + 1] == a[n / 3 * 2] && a[n / 3 * 2 + 1] == a[n]) puts("Yes");
	else puts("No");
	return 0;
}

【B】 Even Degrees

【思路要点】

  • 注意到 M M M 为奇数时问题一定无解。
  • 以下算法对于剩余情况均构造了一组解。
  • 任取一棵生成树,例如 d f s dfs dfs 树,每次找到一个叶子节点 x x x ,将所有的返祖边标为从 x x x 出发,再通过 x x x 的父边调整从 x x x 出发的边数的奇偶性,然后删除 x x x
  • 由于 M M M 为偶数,当所有节点满足出度为偶数时,根节点同样满足。
  • 时间复杂度 O ( N + M ) O(N+M) O(N+M)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {
    x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {
    x = min(x, y); } 
template <typename T> void read(T &x) {
    
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
    
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
    
	write(x);
	puts("");
}
int n, m;
vector <int> a[MAXN];
bool vis[MAXN], ins[MAXN];
bool work(int pos, int fa) {
    
	vis[pos] = true;
	ins[pos] = true;
	bool ans = false;
	for (auto x : a[pos]) {
    
		if (x == fa) continue;
		if (!vis[x]) ans ^= work(x, pos);
		else if (ins[x]) {
    
			ans ^= true;
			printf("%d %d\n", pos, x);
		}
	}
	ins[pos] = false;
	if (fa == 0) return false;
	if (ans) {
    
		printf("%d %d\n", pos, fa);
		return false;
	} else {
    
		printf("%d %d\n", fa, pos);
		return true;
	}
}
int main() {
    
	read(n), read(m);
	for (int i = 1; i <= m; i++) {
    
		int x, y; read(x), read(y);
		a[x].push_back(y);
		a[y].push_back(x);
	}
	if (m & 1) {
    
		puts("-1");
		return 0;
	}
	work(1, 0);
	return 0;
}

【C】 Skolem XOR Tree

【思路要点】

  • N N N 2 2 2 的次幂时无解,因为不可能有路径在那一位上异或和为 1 1 1 ,以下算法对于剩余情况均给出了一组构造。
  • 对于一个异或和为 0 0 0 的点集,我们可以将其仿照样例的解排成一排,即可满足这些点的限制。
  • 注意到对于 4 4 4 的倍数 N N N ,有 N ⊕ ( N + 1 ) ⊕ ( N + 2 ) ⊕ ( N + 3 ) = 0 N\oplus(N+1)\oplus(N+2)\oplus(N+3)=0 N(N+1)(N+2)(N+3)=0
  • 因此,记 1 , 2 , … , N 1,2,\dots,N 1,2,,N 的异或和为 S ( N ) S(N) S(N) ,有
    S ( N ) = { N N ≡ 0   ( m o d   4 ) 1 N ≡ 1   ( m o d   4 ) N + 1 N ≡ 2   ( m o d   4 ) 0 N ≡ 3   ( m o d   4 ) S(N)=\left\{\begin{array}{rcl}N&amp;&amp;{N\equiv0\ (mod\ 4)}\\1&amp;&amp;{N\equiv1\ (mod\ 4)}\\N+1&amp;&amp;{N\equiv2\ (mod\ 4)}\\0&amp;&amp;{N\equiv3\ (mod\ 4)}\end{array} \right. S(N)=N1N+1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值