A – XOR Circle
考虑对仅有的 \(s \leq 3\) 个元素排列顺序然后判就完事了。
// A.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200; int n, ai[MAX_N], si[MAX_N]; map<int, int> mp, tmp; int main() { scanf("%d", &n); for (int i = 1, x; i <= n; i++) scanf("%d", &ai[i]), mp[ai[i]]++; if (mp.size() <= 3) { vector<int> vi; for (auto x : mp) vi.push_back(x.first); bool flag = false; do { int len = vi.size(); tmp.clear(); for (int i = 1; i <= 2; i++) si[i] = vi[(i - 1) % len]; for (int i = 3; i <= n; i++) si[i] = si[i - 1] ^ si[i - 2]; for (int i = 1; i <= n; i++) tmp[si[i]]++; bool cflag = true; for (auto x : tmp) cflag &= mp[x.first] == x.second; flag |= cflag; } while (next_permutation(vi.begin(), vi.end())); puts(flag ? "Yes" : "No"); } else puts("No"); return 0; }
B – Even Degrees
套路题,首先搞出一个 DFS 树,然后贪心的尝试让本子树合法即可,因为当本子树对子树根的父节点产生影响时,也会存在一个返回父亲的边对其进行调整。当然,调整到根还不行那肯定无解了。
// B.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200; typedef pair<int, int> pii; int n, m, head[MAX_N], current, parity[MAX_N]; bool inst[MAX_N], vis[MAX_N]; vector<pii> ansBox; struct edge { int to, nxt; } edges[MAX_N << 1]; void addpath(int src, int dst) { edges[current].to = dst, edges[current].nxt = head[src]; head[src] = current++; } bool dfs(int u, int fa) { vis[u] = inst[u] = true; for (int i = head[u]; i != -1; i = edges[i].nxt) if (!vis[edges[i].to] && edges[i].to != fa) { bool res = dfs(edges[i].to, u); parity[u] ^= !res; if (res) ansBox.push_back(make_pair(edges[i].to, u)); else ansBox.push_back(make_pair(u, edges[i].to)); } inst[u] = false; for (int i = head[u]; i != -1; i = edges[i].nxt) if (inst[edges[i].to] && edges[i].to != fa) if (parity[u]) parity[u] ^= 1, ansBox.push_back(make_pair(u, edges[i].to)); else parity[edges[i].to] ^= 1, ansBox.push_back(make_pair(edges[i].to, u)); return parity[u]; } int main() { memset(head, -1, sizeof(head)); scanf("%d%d", &n, &m); for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u); if (!dfs(1, 0)) for (pii x : ansBox) printf("%d %d\n", x.first, x.second); else puts("-1"); return 0; }
C – Skolem XOR Tree
先参考下面的图:
考虑一个 \(2i \oplus (2i + 1) = 1\) 性质,所以可以直接这样去搞。
如果 \(n\) 是偶数的话,就只能搞出来一条半链,所以我们考虑直接枚举整链的接点,强心接上去即可。
// C.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200; int n; int main() { scanf("%d", &n); if (__builtin_popcount(n) == 1) puts("No"), exit(0); puts("Yes"), printf("1 2\n2 3\n3 %d\n%d %d\n%d %d\n", n + 1, n + 1, n + 2, n + 2, n + 3); for (int i = 4; i < n; i += 2) printf("1 %d\n%d %d\n1 %d\n%d %d\n", i, i, i + 1 + n, i + 1, i + 1, i + n); if (!(n & 1)) { for (int i = 2; i <= n; i++) { int u = i ^ n ^ 1; if (i != 3 && u != 3 && u <= n) { printf("%d %d\n%d %d\n", i, n, u, 2 * n); break; } } } return 0; }
D – Add and Remove
直接搜。
// D.cpp #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll MAX_N = 20, INF = 0x3f3f3f3f3f3f3f3f; int n; ll ai[MAX_N]; ll solve(int l, int r, ll cL, ll cR) { if (l + 1 > r - 1) return 0; ll ret = INF; for (int i = l + 1; i <= r - 1; i++) ret = min(ret, solve(l, i, cL + cR, cR) + solve(i, r, cL, cL + cR) + 1LL * (cL + cR) * ai[i]); return ret; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lld", &ai[i]); printf("%lld\n", solve(1, n, 1, 1) + ai[1] + ai[n]); return 0; }