【比赛链接】
【题解链接】
【A】 Another One Bites The Dust
【思路要点】
- 答案为 2 c + 2 m i n { a , b } + [ a ≠ b ] 2c+2min\{a,b\}+[a\ne b] 2c+2min{a,b}+[a̸=b]。
- 时间复杂度 O ( 1 ) O(1) O(1) 。
【代码】
#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 main() { ll a, b, c; read(a), read(b), read(c); ll ans = 2 * min(a, b); a -= ans / 2, b -= ans / 2, ans += 2 * c; if (a + b) ans += 1; writeln(ans); return 0; }
【B】 Born This Way
【思路要点】
- 最优的方案一定是选取一段 A A A 的前缀,再选取剩余可达的最小的若干个 B B B 。
- 枚举选取的前缀即可,注意 A A A 的前缀可以为空。
- 时间复杂度 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, ta, tb, k; int a[MAXN], b[MAXN]; int main() { read(n), read(m), read(ta), read(tb), read(k); for (int i = 1; i <= n; i++) read(a[i]), a[i] += ta; for (int i = 1; i <= m; i++) read(b[i]); int pos = 0, ans = k; if (k >= n) { puts("-1"); return 0; } for (int i = 0; i <= k; i++) { while (pos < m && a[i + 1] > b[pos + 1]) pos++; chkmax(ans, pos + k - i); } if (ans >= m) puts("-1"); else writeln(b[ans + 1] + tb); return 0; }
【C】 Crazy Diamond
【思路要点】
- 利用 1 , N 1,N 1,N 将 2 , 3 , … , N − 1 2,3,\dots,N-1 2,3,…,N−1 交换至应有的位置上即可。
- 时间复杂度 O ( N ) O(N) O(N) ,操作次数在 3 N 3N 3N 以内。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 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, a[MAXN], home[MAXN]; vector <pair <int, int>> ans; void check(int x, int y) { ans.emplace_back(x, y); swap(home[a[x]], home[a[y]]); swap(a[x], a[y]); } int main() { read(n); for (int i = 1; i <= n; i++) read(a[i]), home[a[i]] = i; for (int i = 2; i <= n - 1; i++) if (home[i] != i) { int pos = home[i]; if (2 * abs(pos - 1) >= n) { check(pos, 1); if (2 * abs(1 - i) >= n) check(1, i); else { check(1, n); check(n, i); } } else { check(pos, n); if (2 * abs(n - i) >= n) check(n, i); else { check(1, n); check(1, i); } } } if (home[1] != 1) check(1, n); writeln(ans.size()); for (auto x : ans) printf("%d %d\n", x.first, x.second); return 0; }
【D】 Dirty Deeds Done Dirt Cheap
【思路要点】
- 将数对分为 x > y x>y x>y 的数对和 x < y x<y x<y 的数对。
- 对于 x < y x<y x<y 的数对,按照 x x x 降序排序,可以使得其全部使用。
- 对于 x > y x>y x>y 的数对,按照 y y y 升序排序,可以使得其全部使用。
- 时间复杂度 O ( N L o g N ) O(NLogN) O(NLogN) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 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, a[MAXN], b[MAXN]; vector <int> inc, dec; bool cmp(int x, int y) { return a[x] > a[y]; } bool cnp(int x, int y) { return b[x] < b[y]; } int main() { read(n); vector <int> inc, dec; for (int i = 1; i <= n; i++) { read(a[i]), read(b[i]); if (a[i] < b[i]) inc.push_back(i); else dec.push_back(i); } if (inc.size() > dec.size()) { writeln(inc.size()); sort(inc.begin(), inc.end(), cmp); for (auto x : inc) printf("%d ", x); printf("\n"); } else { writeln(dec.size()); sort(dec.begin(), dec.end(), cnp); for (auto x : dec) printf("%d ", x); printf("\n"); } return 0; }
【E】 Earth Wind and Fire
【思路要点】
- 排序两个数组,记 d i = s i − t i d_i=s_i-t_i di=si−ti ,则首先要求 ∑ d i = 0 \sum d_i=0 ∑di=0 。
- 可以发现一次操作使得靠前的一个 d i d_i di 增加,靠后的一个 d i d_i di 减少,最终要求全部的 d i d_i di 变为零。
- 可以直接采用类似括号序列的方式贪心。
- 时间复杂度 O ( N L o g N ) O(NLogN) O(NLogN) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 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(""); } struct info {int x, y; ll z; }; vector <info> ans; ll s[MAXN], t[MAXN], p[MAXN], a[MAXN]; bool cmp(int x, int y) { return s[x] < s[y]; } int main() { int n; read(n); for (int i = 1; i <= n; i++) read(s[i]), p[i] = i; for (int i = 1; i <= n; i++) read(t[i]); sort(t + 1, t + n + 1); sort(p + 1, p + n + 1, cmp); sort(s + 1, s + n + 1); int sum = 0; for (int i = 1; i <= n; i++) { a[i] = s[i] - t[i]; sum += a[i]; } if (sum != 0) { puts("NO"); return 0; } int pos = 0; for (int i = 1; i <= n; i++) { if (a[i] > 0) { puts("NO"); return 0; } while (a[i] < 0) { while (a[pos] <= 0) pos++; int d = min(-a[i], a[pos]); ans.push_back((info) {p[i], p[pos], d});; a[i] += d, a[pos] -= d; } } puts("YES"); writeln(ans.size()); for (auto x : ans) printf("%d %d %lld\n", x.x, x.y, x.z); return 0; }
【F】 Foo Fighters
【思路要点】
- 将 s s s 的第 i i i 位设为 1 1 1 等价于取反 m a s k mask mask 第 i i i 位为 1 1 1 的数的权值。
- 将各数按照 m a s k mask mask 最高数位 i i i 分类,则我们可以用 s s s 的第 i i i 位保证各组数的权值和非正/非负,同时由于数据保证初始权值和非零,我们得到的结果也一定非零。
- 时间复杂度 O ( N L o g V ) O(NLogV) O(NLogV) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 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; ll a[MAXN], mask[MAXN], s; int main() { read(n); for (int i = 1; i <= n; i++) { read(a[i]), read(mask[i]); s += a[i]; } if (s < 0) { for (int i = 1; i <= n; i++) a[i] = -a[i]; } ll ans = 0; for (int p = 0; p <= 61; p++) { ll bit = 1ll << p, cur = 0; for (int i = 1; i <= n; i++) if ((mask[i] & bit) && (mask[i] < (2 * bit))) cur += a[i]; if (cur > 0) { ans ^= bit; for (int i = 1; i <= n; i++) if (mask[i] & bit) a[i] = -a[i]; } } writeln(ans); return 0; }
【G】 Gold Experience
【思路要点】
- 将 a i a_i ai 各质因数的指数设为一,答案不变。
- 计算一个位置的出边个数可以使用莫比乌斯反演。
- 找到一个与至少两个点没有边相连的点 x x x 。
- 若无法找到该 x x x ,则给定图的补图仅由大小为 1 , 2 1,2 1,2 的联通块构成,不难选出一个大小在 N 2 \frac{N}{2} 2N 以内的独立集。
- 否则,首先删除 x x x ,以及与 x x x 没有边相连的两个点 y , z y,z y,z 。
- 记剩余点集合为 R R R ,若 R R R 中存在至少 k k k 个与其余点均有边的点,则可以选取它们作为一个团。
- 否则,二分出 p o s pos pos 满足 { 1 , 2 , … , p o s } \{1,2,\dots,pos\} {1,2,…,pos} 中尚不能选出 k − 3 k-3 k−3 个点,满足各个点与选出的至少一个点没有边相连,而 { 1 , 2 , … , p o s + 1 } \{1,2,\dots,pos+1\} {1,2,…,pos+1} 中可以。
- 记 S S S 为 { 1 , 2 , … , p o s } \{1,2,\dots,pos\} {1,2,…,pos} 中选出的集合, T T T 为 { 1 , 2 , … , p o s + 1 } \{1,2,\dots,pos+1\} {1,2,…,pos+1} 中选出的集合。
- 删除 T T T 中新出现的与 p o s + 1 pos+1 pos+1 没有边相连的点,直到 ∣ T ∣ = k − 2 |T|=k-2 ∣T∣=k−2 ,再将初始时找到的 x , y x,y x,y 加入 T T T 中即可。
- 时间复杂度 O ( N L o g N × 2 8 ) O(NLogN\times 2^{8}) O(NLogN×28) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int MAXV = 1e7 + 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 tot, prime[MAXV], f[MAXV], miu[MAXV]; void sieve(int n) { miu[1] = 1; for (int i = 2; i <= n; i++) { if (f[i] == 0) prime[++tot] = f[i] = i, miu[i] = -1; for (int j = 1; j <= tot && prime[j] <= f[i]; j++) { int tmp = prime[j] * i; if (tmp > n) break; f[tmp] = prime[j]; if (prime[j] == f[i]) miu[tmp] = 0; else miu[tmp] = -miu[i]; } } } int func(int x) { int ans = 1; while (x != 1) { int tmp = f[x]; ans *= f[x]; while (x % tmp == 0) x /= tmp; } return ans; } int n, k, a[MAXN], b[MAXN], home[MAXN], cnt[MAXV]; bool iskey[MAXN]; vector <int> d[MAXV]; void work(int x) { memset(cnt, 0, sizeof(cnt)); for (int i = 1; i <= x; i++) if (!iskey[i]) { for (auto x : d[a[i]]) cnt[x]++; } for (int i = 1; i <= x; i++) if (!iskey[i]) { b[i] = 0; for (auto x : d[a[i]]) b[i] += miu[x] * cnt[x]; } } int main() { read(n), read(k), sieve(1e7); for (int i = 1; i <= n; i++) { read(a[i]), home[i] = i, a[i] = func(a[i]); d[a[i]].clear(); for (int j = 1; j * j <= a[i]; j++) if (a[i] % j == 0) { cnt[j]++, d[a[i]].push_back(j); if (j * j != a[i]) cnt[a[i] / j]++, d[a[i]].push_back(a[i] / j); } } int pos = 0; for (int i = 1; i <= n; i++) { for (auto x : d[a[i]]) b[i] += miu[x] * cnt[x]; if (b[i] >= 2) pos = i; } if (pos == 0) { set <int> s; memset(cnt, 0, sizeof(cnt)); for (int i = 1; i <= n; i++) { b[i] = 0; for (auto x : d[a[i]]) b[i] += miu[x] * cnt[x]; if (b[i] == 0 && s.size() < k) { s.insert(i); for (auto x : d[a[i]]) cnt[x]++; } } for (auto x : s) printf("%d ", x); return 0; } vector <int> key; key.push_back(pos), iskey[pos] = true; for (int i = 1; i <= n; i++) if (__gcd(a[i], a[pos]) == 1 && key.size() < 3) key.push_back(i), iskey[i] = true; work(n); int zeros = 0; for (int i = 1; i <= n; i++) if (!iskey[i] && b[i] == 0) zeros++; if (zeros >= k) { for (int i = 1; i <= n; i++) if (!iskey[i] && b[i] == 0 && k != 0) { printf("%d ", i); k--; } } else { int l = 0, r = n; while (l < r) { int mid = (l + r) / 2; int cnt = 3; work(mid); for (int i = 1; i <= mid; i++) if (!iskey[i] && b[i] != 0) cnt++; if (cnt >= k) r = mid; else l = mid + 1; } set <int> s; work(l); for (auto x : key) s.insert(x); for (int i = 1; i <= l; i++) if (!iskey[i] && b[i] != 0) s.insert(i); if (s.size() == k) { for (auto x : s) printf("%d ", x); } else { set <int> t; work(l - 1); for (auto x : key) t.insert(x); for (int i = 1; i <= l - 1; i++) if (!iskey[i] && b[i] != 0) t.insert(i); t.insert(l); bool flg = false; for (int i = 1; i <= l - 1 && (!flg || t.size() < k); i++) if (__gcd(a[l], a[i]) == 1) t.insert(i), flg = true; if (t.size() > k) t.erase(key.back()); for (auto x : t) printf("%d ", x); } } return 0; }