【比赛链接】
【题解链接】
【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 a⊕b , 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&&{N\equiv0\ (mod\ 4)}\\1&&{N\equiv1\ (mod\ 4)}\\N+1&&{N\equiv2\ (mod\ 4)}\\0&&{N\equiv3\ (mod\ 4)}\end{array} \right. S(N)=⎩⎪⎪⎨⎪⎪⎧N1N+1