A. Square?
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int a, b, c, d;std::cin >> a >> b >> c >> d;if (a == b && b == c && c == d) {std::cout << "Yes\n";} else {std::cout << "NO\n";}
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}
B. Your Name
题意:判断两个字符串是不是组成的字符一样。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n;std::cin >> n;std::string s, t;std::cin >> s >> t;int cnt[26]{};for (auto & c : s) {++ cnt[c - 'a'];}for (auto & c : t) {if ( -- cnt[c - 'a'] < 0) {std::cout << "NO\n";return;}}std::cout << "YES\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}
C. Isamatdin and His Magic Wand!
题意:一个数组,你可以交换两个奇偶性不同的数,求交换任意次数组的最小字典序。
如果只有偶数或者奇数无法操作,否则一定可以达到升序。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n;std::cin >> n;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}bool f[2]{};for (auto & x : a) {f[x & 1] = 1;}if (f[0] && f[1]) {std::ranges::sort(a);}for (int i = 0; i < n; ++ i) {std::cout << a[i] << " \n"[i == n - 1];}
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}
D. Yet Another Array Problem
题意:找一个最小的大于\(1\)的数,使得数组里有一个数和它互质。
这个数一定是一个质数,如果不是质数,则可以用它的最小质因子替换它,这样依然和另一个数互质。
那么枚举质数即可,如果因为\(a_i \leq 10^{18}\),其包含的不同质因子不超过\(20\)个,那么很快就能找到答案。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;std::vector<int> minp, primes;void sieve(int n) {minp.assign(n + 1, 0);primes.clear();for (int i = 2; i <= n; ++ i) {if (minp[i] == 0) {minp[i] = i;primes.push_back(i);}for (auto p : primes) {if (i * p > n) {break;}minp[i * p] = p;if (p == minp[i]) {break;}}}
}void solve() {int n;std::cin >> n;std::vector<i64> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}for (auto & p : primes) {for (int i = 0; i < n; ++ i) {if (std::gcd(a[i], p) == 1) {std::cout << p << "\n";return;}}}std::cout << -1 << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;sieve(1000);std::cin >> t;while (t -- ) {solve();}return 0;
}
E. khba Loves to Sleep!
题意:\([0, x]\)上有\(n\)个点,你需要选\(k\)个不同的位置,使得这\(n\)个点到其中一个位置的最小距离最大。
考虑二分。
先把数组排序,如果二分距离为\(d\),对于两个点\(a_i, a_{i+1}\)之间,可以选的位置为\([a_i + d, a_{i+1} - d]\)。判断这些位置够不够\(k\)个并且记录一下方案就行。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n, k, x;std::cin >> n >> k >> x;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}std::ranges::sort(a);if (a.back() != x) {a.push_back(2 * x);}auto check = [&](int d, bool flag) -> std::pair<bool, std::vector<int>> {std::vector<int> res;if (d == 0) {if (flag) {for (int i = 0; i < k; ++ i) {res.push_back(i);}}return {true, res};}int last = -2 * x;int cnt = 0;for (int i = 0; i < a.size(); ++ i) {int l = std::max(0, last + d), r = std::min(x, a[i] - d);if (l <= r) {cnt += r - l + 1;if (flag) {while (l <= r && res.size() < k) {res.push_back(l);++ l;}}}last = a[i];}return {cnt >= k, res};};int lo = 0, hi = x;while (lo < hi) {int mid = lo + hi + 1 >> 1;if (check(mid, false).first) {lo = mid;} else {hi = mid - 1;}}auto ans = check(lo, true).second;for (int i = 0; i < k; ++ i) {std::cout << ans[i] << " \n"[i == k - 1];}
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}
F. Tree, TREE!!!
题意:对于一棵树,求对于每个点为根的情况下,选任意\(k\)个点能凑出多少不同的\(lca\)。求每个点的答案的和。
考虑对于\(u\),有多少点为根选\(k\)个点可以凑出\(lca = u\)。
那么可以先任意选一个点为根,比如\(1\)。然后\(dfs\)一下记录子树节点个数。那么对于\(u\)子树外的点,不管是谁为根\(u\)的子树依然是这个样子,那么如果\(size_u \geq k\),其它\(n - size_u\)个都可以作为答案。对于\(u\)的一个儿子\(v\),它的子树的任意一个点为根,\(u\)的子树就是\(n - size_v\)个点。那么如果\(n - size_v \geq k\),有\(size_v\)个答案。最后以\(u\)为根显然也是可以的。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;void solve() {int n, k;std::cin >> n >> k;std::vector<std::vector<int>> adj(n);for (int i = 1; i < n; ++ i) {int u, v;std::cin >> u >> v;-- u, -- v;adj[u].push_back(v);adj[v].push_back(u);}i64 ans = 0;std::vector<int> size(n);auto dfs = [&](auto && self, int u, int fa) -> void {size[u] = 1;for (auto & v : adj[u]) {if (v == fa) {continue;}self(self, v, u);if (n - size[v] >= k) {ans += size[v];}size[u] += size[v];}if (size[u] >= k) {ans += n - size[u];}ans += 1;};dfs(dfs, 0, -1);std::cout << ans << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}
G. Mukhammadali and the Smooth Array
题意:一个数组\(a\),你可以花费\(c_i\)把\(a_i\)改成任何数。求让数组不递减的最小花费。
可以看作选一部分不操作,其它的操作的最小花费。
那么选出不操作的这一部分必须是不递减的。那么我们要让这一部分的\(c_i\)的和最大,这样另一部分的花费才会更小。
那么就是一个\(dp\),\(f_i = c_i + f_j(j <i, a_j \leq a_i)\)。
这是典题,可以用树状数组优化为\(nlogn\)。维护一下前缀最大值就可以。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;template <class T>
struct Fenwick {int n;std::vector<T> tr;Fenwick(int _n) {init(_n);}void init(int _n) {n = _n;tr.assign(_n + 1, T{});}void add(int x, const T &v) {for (int i = x; i <= n; i += i & -i) {tr[i] = tr[i] + v;}}T query(int x) {T res{};for (int i = x; i; i -= i & -i) {res = res + tr[i];}return res;}T sum(int l, int r) {return query(r) - query(l - 1);}
};struct Info {i64 max = 0;
};Info operator + (const Info & a, const Info & b) {return {std::max(a.max, b.max)};
}void solve() {int n;std::cin >> n;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}std::vector<int> c(n);for (int i = 0; i < n; ++ i) {std::cin >> c[i];}auto b = a;std::ranges::sort(b);b.erase(std::unique(b.begin(), b.end()), b.end());for (auto & x : a) {x = std::ranges::lower_bound(b, x) - b.begin() + 1;}int m = b.size();Fenwick<Info> tr(m + 1);for (int i = 0; i < n; ++ i) {tr.add(a[i], Info{tr.query(a[i]).max + c[i]});}std::cout << std::accumulate(c.begin(), c.end(), 0ll) - tr.query(m).max << "\n";
}int main() {std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);int t = 1;std::cin >> t;while (t -- ) {solve();}return 0;
}