A. 来!选!队!长
签到题。
由于队长的战力要乘以二,因此‘我’的队伍最大战力为 \(r1=a_1 \times 2+a_2+a_3+a_4+a_5\),好友队伍的最小战力为 \(r2=b_1+b_2+b_3+b_4+b_5 \times 2\)。
题目问是否有可能使得‘我’的队伍战力大于好友队伍战力,因此只需判断 \(r1 > r2\) 这个条件是否成立即可。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <bits/stdc++.h>
#define x first #define y second #define endl '\n'
using namespace std;
using ll = long long; using PII = pair<int, int>;
int read(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') f = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;} void print(int x){if (x < 0){putchar('-');x = -x;}if (x > 9) print(x / 10);putchar(x % 10 + '0');}
void solve() { int r1 = 0, r2 = 0; for (int i = 0; i < 5; i++) { int x; cin >> x; r1 += x; if (!i) r1 += x; } for (int i = 0; i < 5; i++) { int x; cin >> x; r2 += x; if (i == 4) r2 += x; } if (r1 > r2) cout << "YES" << endl; else cout << "NO" << endl; }
int main() { ios::sync_with_stdio(false); cin.tie(0);
int T = 1; while (T--) { solve(); }
return 0; }
|
B. 抽我选的效率曲
分类讨论。
分别统计代号为 \(k\) 的歌曲数以及总歌曲数,设为 \(c1\) 和 \(c2\)。
- \(c1=0,c2 = 0\),代表没有人选歌,输出 \(1/1000\)。
- \(c1 = 0,c2 \neq 0\),代表有人选歌,但是没有人选代号为 \(k\) 的歌,输出 \(0/1\)。
- \(c1 \neq 0,c2 \neq 0\),代表有人选歌,并且也有人选代号为 \(k\) 的歌,输出 \(c1/c2\),需要注意的是,当 \(c1=2,c2=4\) 时,需要约分成 \(1/2\)。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include <bits/stdc++.h>
#define x first #define y second #define endl '\n'
using namespace std;
using ll = long long; using PII = pair<int, int>;
int read(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') f = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;} void print(int x){if (x < 0){putchar('-');x = -x;}if (x > 9) print(x / 10);putchar(x % 10 + '0');}
void solve() { vector<int> a(5); for (int i = 0; i < 5; i++) cin >> a[i]; int k; cin >> k;
int c1 = 0, c2 = 0; for (int i = 0; i < 5; i++) { if (a[i] == k) c1++; if (a[i]) c2++; }
if (!c2) cout << "1/1000" << endl; else if (!c1) cout << "0/1" << endl; else { int g = gcd(c1, c2); c1 /= g, c2 /= g; cout << c1 << '/' << c2 << endl; } }
int main() { ios::sync_with_stdio(false); cin.tie(0);
int T = 1; cin >> T; while (T--) { solve(); }
return 0; }
|
C. 睡前床边看LIVE
可以确定的是,对于相同的颜色,对应的豆腐人的回答都是相同的。因此,颜色的种类数至少是豆腐人回答的种类数。
接下来可以豆腐人回答的种类数进行分类讨论。
- 种类数为 \(1\),所有人回答都是一样的。若 \(\lfloor\frac{a_0}{n}\rfloor>1\),则可以每 \(a_0\) 个为一种颜色,例如 \(2,2,2,2,2\),颜色可以分为 \(A,A,B,B,C\)。若 \(a_0+1=n\),则所有人都为一样的颜色即可合理分配。剩下的其他情况都为 \(Lie\)。
- 种类数为 \(2\)。首先把数组排序,此时\(a_0\) 为第一种回答,\(a_{n-1}\) 为第二种回答,设\(c_0\) 为回答是 \(a_0\) 的个数,\(c_{n-1}\) 为回答是 \(a_{n-1}\) 的个数。则当且仅当 \(c0=a_{n-1}\) 并且 \(a_0+1=a_{n-1}\) 时,才能输出 \(Other\),其他情况全都输出 \(Lie\)。分配方案为 \(c_0\) 个回答 \(a_0\) 全部一个颜色,\(c_{n-1}\) 个回答 \(a_{n-1}\) 染成其他颜色,并且互不相同
- 种类数大于等于 \(3\)。可以发现,无法找到合法的颜色分配方案,统一输出 \(Lie\)。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include <bits/stdc++.h>
#define x first #define y second #define endl '\n'
using namespace std;
using ll = long long; using PII = pair<int, int>;
int read(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') f = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;} void print(int x){if (x < 0){putchar('-');x = -x;}if (x > 9) print(x / 10);putchar(x % 10 + '0');}
void solve() { int n; cin >> n;
vector<int> a(n); for (int i = 0; i < n; i++) cin >> a[i];
sort(a.begin(), a.end());
map<int, int> p; for (int i = 0; i < n; i++) p[a[i]]++;
if (p.size() > 2) cout << "Lie" << endl; else if (p.size() == 2) { int c1 = p[a[0]], c2 = p[a[n - 1]]; if (c1 == a[n - 1] && a[0] + 1 == a[n - 1]) cout << "Other" << endl; else cout << "Lie" << endl; } else { if (n / a[0] > 1 || n - 1 == a[0]) cout << "Other" << endl; else cout << "Lie" << endl; } }
int main() { ios::sync_with_stdio(false); cin.tie(0);
int T = 1; cin >> T; while (T--) { solve(); }
return 0; }
|
D. 世界树上找米库
转化题意,\(Sekai\) 是叶子节点,对于每个节点,它的权值为这个节点到最近叶子节点的距离,要求我们找到权值最大的节点,并从小到大输出节点编号。
标准的多源 \(bfs\) 问题,设 \(f_i\) 为节点 \(i\) 到最近叶子节点的距离,以每个叶子节点为起点跑一遍 \(bfs\) 即可。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include <bits/stdc++.h>
#define x first #define y second #define endl '\n'
using namespace std;
using ll = long long; using PII = pair<int, int>;
int read(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') f = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;} void print(int x){if (x < 0){putchar('-');x = -x;}if (x > 9) print(x / 10);putchar(x % 10 + '0');}
void solve() { int n; cin >> n;
vector<vector<int>> h(n + 1); for (int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; h[u].push_back(v), h[v].push_back(u); }
vector<int> f(n + 1, 1e9); auto bfs = [&](int st) { f[st] = 0; queue<int> q; q.push(st); while (q.size()) { int u = q.front(); q.pop(); for (auto v: h[u]) { if (f[v] <= f[u] + 1) continue; f[v] = f[u] + 1; q.push(v); } } }; for (int i = 1; i <= n; i++) if (h[i].size() == 1) bfs(i);
int maxv = 0; vector<int> s; for (int i = 1; i <= n; i++) { if (f[i] >= maxv) { if (f[i] > maxv) s.clear(); maxv = f[i]; s.push_back(i); } } sort(s.begin(), s.end());
cout << s.size() << endl; for (auto x: s) cout << x << ' '; cout << endl; }
int main() { ios::sync_with_stdio(false); cin.tie(0);
int T = 1; cin >> T; while (T--) { solve(); }
return 0; }
|
E. 森友会里打音游
\(dp\),设 \(f_i\) 为遍历到 \(i\),并保留第 \(i\) 个物品,所需删除的最小物品数。
在进行思考前,我们需要知道枚举 \(a_i\) 的因数,所需的时间复杂度是 \(O(\sqrt{a_i})\),而题目中 \(a_i\) 的上界为 \(n\),因此整体复杂度应该往 \(O(n \sqrt{n})\) 去靠拢。
对于 \(a_i\),设它的因数为 \(c_1,c_2,c_3,...,c_j\),要分别考虑要把 \(a_i\) 的左边变成它的因数还是倍数。 * 变成因数。设左边离 \(i\) 最近因数的下标分别为 \(p_1,p_2,p_3...p_j\),则有 \(f_i= min\{f_i,f_{p_1}+i-p_1-1,f_{p_2}+i-p_2-1,f_{p_3}+i-p_3-1,...,f_{p_j}+i-p_j-1\}\)。 * 变成倍数。由于倍数的枚举没有因数那么方便,因此,当我们处理完一个 \(f_i\) 时,可以考虑对它右边的因数进行转移。设右边离 \(i\) 最近因数的下标分别为 \(p_1,p_2,p_3,...,p_j\),则有 \(f_{p_j}=min(f_{p_j},f_i+p_j-i-1)\)。也就是说,当我们遍历到 第 \(i\) 个物品的时候,对于把它左边的数变成它的倍数的情况,已经提前处理完成了。
最终答案为 \(\max_{1 \le i \le n} (n-(f_i + n - i))\)。
时间复杂度 \(O(n \sqrt{n})\)。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #include <bits/stdc++.h>
#define x first #define y second #define endl '\n'
using namespace std;
using ll = long long; using PII = pair<int, int>;
int read(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') f = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;} void print(int x){if (x < 0){putchar('-');x = -x;}if (x > 9) print(x / 10);putchar(x % 10 + '0');}
void solve() { int n; cin >> n;
vector<int> a(n + 1); for (int i = 1; i <= n; i++) cin >> a[i];
vector<vector<int>> st(n + 1); for (int i = n; i >= 1; i--) st[a[i]].push_back(i);
vector<int> pos(n + 1, 0), f(n + 1, n); for (int i = 1; i <= n; i++) { f[i] = min(f[i], i - 1); for (int j = 1; j <= a[i] / j; j++) { if (a[i] % j) continue; f[i] = min(f[i], f[pos[j]] + i - pos[j] - 1); f[i] = min(f[i], f[pos[a[i] / j]] + i - pos[a[i] / j] - 1); } st[a[i]].pop_back(); for (int j = 1; j <= a[i] / j; j++) { if (a[i] % j) continue; if (st[j].size()) { int p = st[j].back(); f[p] = min(f[p], f[i] + p - i - 1); } if (st[a[i] / j].size()) { int p = st[a[i] / j].back(); f[p] = min(f[p], f[i] + p - i - 1); } } pos[a[i]] = i; }
int res = 0; for (int i = 1; i <= n; i++) res = max(res, -f[i] + i);
cout << res << endl; }
int main() { ios::sync_with_stdio(false); cin.tie(0); int T = 1; cin >> T; while (T--) { solve(); } return 0; }
|
F. 这招太狠了烤学妹
首先可以注意到,如果要对一段长度为 \(x\) 的 \(o\) 序列修改 \(c\) 次,一定是均等的分成 \(c+1\) 段对分数的贡献最小,设这个切分后分数计算函数为 \(calc(x,c)\)(具体实现见代码)。
我们可以考虑先把所有 \(o\) 序列全部处理出来,然后用优先队列来进行维护,优先选择 \(calc(x,c)-calc(x,c+1)\) 最大的段。
时间复杂度 \(O(nlogn)\)。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include <bits/stdc++.h>
#define x first #define y second #define endl '\n'
using namespace std;
using ll = long long; using PII = pair<int, int>;
int read(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') f = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}return x * f;} void print(int x){if (x < 0){putchar('-');x = -x;}if (x > 9) print(x / 10);putchar(x % 10 + '0');}
ll calc(ll x, ll c) { x -= c; return (1 + x / (c + 1)) * (x / (c + 1)) / 2 * (c + 1) + x % (c + 1) * (x / (c + 1) + 1); }
struct Node { ll x, c; bool operator< (const Node &B) const { return calc(x, c) - calc(x, c + 1) < calc(B.x, B.c) - calc(B.x, B.c + 1); } };
void solve() { int n, k; string s; cin >> n >> k >> s;
priority_queue<Node> q; int l = 0, r = 0; while (r < n) { if (s[l] != s[r]) { if (s[l] == 'o') q.push({r - l, 0}); l = r; } r++; } if (s[l] == 'o') q.push({r - l, 0});
while (k-- && q.size()) { auto [x, c] = q.top(); q.pop(); if (c + 1 < x) q.push({x, c + 1}); }
ll res = 0; while (q.size()) { auto [x, c] = q.top(); q.pop(); res += calc(x, c); }
cout << res << endl; }
int main() { ios::sync_with_stdio(false); cin.tie(0);
int T = 1; cin >> T; while (T--) { solve(); }
return 0; }
|