A.Divisibility Problem
题意:
给两个数,每次操作可以使,问最少几次操作后是的倍数。
题解:
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 1e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 998244353; void solve() { int a, b; scanf("%d%d", &a, &b); if (a % b == 0) { puts("0"); return; } if (a <= b) printf("%d\n", b - a); else printf("%d\n", b - a % b); } int main() { int t; for (scanf("%d", &t); t >= 1; t--) solve(); }
B.K-th Beautiful String
题意:
长度为的字符串包含个和个,求按照字典序排列的第个。
题解:
观察样例,左边的的位置出现次数倒数第二位有个,倒数第三位有个,倒数第四位有个,确定后再确定右边的的出现位置即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 1e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 998244353; void solve() { int n, k; scanf("%d%d", &n, &k); int l = 1; while (k > l) k -= l, l++; l++; int r = k; for (int i = n; i >= 1; i--) { if (i == l || i == r) putchar('b'); else putchar('a'); } puts(""); } int main() { int t; for (scanf("%d", &t); t >= 1; t--) solve(); }
C.Ternary XOR(构造)
题意:
规定三进制下的运算,现给定长度为的,要求构造,并使得尽可能小。
题解:
先讲最前面的和平分,遇到的第一个给,之后所有的值全给,此时的就是最小的
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 1e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 998244353; void solve() { int n; scanf("%d", &n); string a, b, c; cin >> c; bool flag = true; for (auto i : c) { if (flag) { if (i == '0') a += '0', b += '0'; if (i == '1') a += '1', b += '0', flag = false; if (i == '2') a += '1', b += '1'; } else { a += '0'; b += i; } } cout << a << endl << b << endl; } int main() { int t; for (scanf("%d", &t); t >= 1; t--) solve(); }
D.Carousel(构造)
题意:
个动物围成一个环,现在要给动物上色,要求不能给相邻的不同动物上同一种颜色,问最少几种颜色可以满足条件。
题解:
观察样例,其实可以得出结论的
- 全同色,1种
- 不存在相邻的相同动物且为奇数,3种。(前面1,2间隔最后一个3)
- 其余情况两种。偶数(12121212)奇数(找组相邻相同的把12反向)
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 998244353; int a[maxn]; void solve() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); a[0] = a[n]; int f1 = 0, f2 = 0; for (int i = 1; i <= n; i++) { if (a[i] != a[i - 1]) f1 = 1; else f2 = i; } if (!f1) { puts("1"); for (int i = 1; i <= n; i++) printf("%d ", 1); puts(""); return; } if (!f2 && (n & 1)) { puts("3"); for (int i = 1; i < n; i++) printf("%d ", (i & 1) ? 1 : 2); puts("3"); } else { puts("2"); if (n & 1) { for (int i = 1; i < f2; i++) printf("%d ", (i & 1) ? 1 : 2); for (int i = f2; i <= n; i++) printf("%d ", (i & 1) ? 2 : 1); puts(""); } else { for (int i = 1; i <= n; i++) printf("%d ", (i & 1) ? 1 : 2); puts(""); } } } int main() { int t; for (scanf("%d", &t); t >= 1; t--) solve(); }
E.Tree Queries(LCA)
题意:
给定一棵个节点且以节点为根的有根树。对于个询问,每个询问给个点,问是否存在从出发的一条链使得这个点都在链上,或者距这条链上一点的距离为
题解:
在个点里找深度最大的点为该链终点。判断一下其他的点是否满足条件。只要判断(当前结点,最深结点) = 当前结点 或者 (当前结点,最深结点)=当前结点的父亲。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 7; int n, q, f[25][maxn], h[maxn]; vector<int> G[maxn]; void dfs(int x) { for (int i = 0; i < G[x].size(); i++) { int v = G[x][i]; if (v == f[0][x]) continue; f[0][v] = x; h[v] = h[x] + 1; dfs(v); } } void lca_init() { dfs(1); for (int i = 1; i <= 20; i++) for (int j = 1; j <= n; j++) f[i][j] = f[i - 1][f[i - 1][j]]; } int lca(int x, int y) { if (h[x] < h[y]) swap(x, y); for (int i = 20; i >= 0; i--) if ((h[x] - h[y]) >> i) x = f[i][x]; if (x == y) return x; for (int i = 20; i >= 0; i--) { if (f[i][x] != f[i][y]) { x = f[i][x]; y = f[i][y]; } } return f[0][x]; } void solve() { int k; scanf("%d", &k); vector<int> node; int mxdep = -1, mxnode = -1; for (int i = 0, x; i < k; i++) { scanf("%d", &x); node.push_back(x); if (h[x] > mxdep) { mxdep = h[x]; mxnode = x; } } for (auto u : node) { int LCA = lca(u, mxnode); if (LCA != u && LCA != f[0][u]) { puts("NO"); return; } } puts("YES"); } int main() { int m; scanf("%d%d", &n, &m); for (int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } lca_init(); while (m--) solve(); return 0; }
F.Make k Equal
题意:
给定由个数的数组,每次操作可以将任意一个最大值或任意一个最小值。问操作几次使得至少存在个相等的数字。
题解:
我们假设个相等的数字都是,只有先将所有小于的数字变为或者所有大于的数字变为才能够操作成。所以我们只要把a排序后维护一个前缀和和一个后缀和。计算出前缀变成和后缀变成的次数就可以简单的计算出答案。扫描一遍取最小值即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int maxn = 2e5 + 5; const int INF = 0x3f3f3f3f; const ll INFL = 0x3f3f3f3f3f3f3f3fll; const int mod = 998244353; ll a[maxn]; set<ll> s; map<ll, ll> mp; int main() { int n, k; scanf("%d%d", &n, &k); ll suml = 0, sumr = 0, cntl = 0, cntr = n; for (int i = 0; i < n; i++) { scanf("%lld", &a[i]); sumr += a[i]; s.insert(a[i]); mp[a[i]]++; } ll res = INFL; for (auto i : s) { if (mp[i] >= k) { puts("0"); return 0; } sumr -= mp[i] * i; cntr -= mp[i]; ll cnt = k - mp[i]; ll l = cntl * (i - 1) - suml; ll r = sumr - cntr * (i + 1); if (cntl >= cnt) res = min(res, l + cnt); if (cntr >= cnt) res = min(res, r + cnt); res = min(res, l + r + cnt); suml += mp[i] * i; cntl += mp[i]; } printf("%lld\n", res); return 0; }