A. AUS
题目大意
给你三个字符串S1、S2、S3,问是否存在一种字母映射方式使得F(S1)等于F(S2)但是不等于F(S3)
解题思路
想要让S1、S2相等首先显然要满足长度相等,因此可以先把长度不相等的时候的存在关系判断出来,对于三个字符串都相等的情况,可以通过遍历修改字符串让S1变成S2,或者S2变成S1,逐字符比较不相等修改即可,这样的修改Python有一个内置函数replace(C++的只替换指定位置)可以直接替换完成映射,最后只需要查看是不是满足题目要求即可
代码实现
for _ in range(int(input())):s1 = input()s2 = input()s3 = input()if len(s1) != len(s2):print("NO")elif len(s1) != len(s3):print("YES")else:S1 = [s1, s1]S2 = [s2, s2]S3 = [s3, s3]for i in range(len(s1)):A, B = S1[0][i], S2[0][i]if A != B:S1[0] = S1[0].replace(B, A)S2[0] = S2[0].replace(B, A)S3[0] = S3[0].replace(B, A)A, B = S1[1][i], S2[1][i]if A != B:S1[1] = S1[1].replace(A, B)S2[1] = S2[1].replace(A, B)S3[1] = S3[1].replace(A, B)if S1[0] == S2[0] and S1[0] != S3[0] or S1[1] == S2[1] and S1[1] != S3[1]:print("YES")else:print("NO")
K. Kind of Bingo
题目大意
给你一个n*m的网格,再给你一个排列表示标记的顺序,问修改操作顺序后让一行网格被标记最少要操作多少次
解题思路
根据给出的这个数值大小即可得知当前正在标记哪一行, 允许修改k次则保证至少能把k个靠后的操作放到前面来,因此我们只需要找到第一个满足m-k(至少得是0)的行是哪一行,再对这一行改变操作即可,注意最后的答案要和m取max——至少操作m次才能填充m个
代码实现
#include <bits/stdc++.h>int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);int t;std::cin >> t;while (t--) {int n, m, k, ok = -1;std::cin >> n >> m >> k;std::vector<int> p(n * m), f(n);for (int i = 0; i < n * m; i++) {std::cin >> p[i];int x = (p[i] - 1) / m;f[x]++;if (ok == -1 && f[x] >= std::max(0, m - k)) {ok = x;}}std::vector<int> ans;for (int i = 0; i < n * m; i++) {int x = (p[i] - 1) / m;if (x == ok) {ans.push_back(i + 1);}}std::cout << std::max(m, ans[std::max(0, m - k - 1)]) << "\n";}
}
E. Elevator II
题目大意
有一部电梯每次只能乘坐1人,上升消耗r-l,下降无消耗,问把所有人送到目的地的最小消耗之和并给出安排方案
解题思路
先让电梯升到最高处,上升过程中的人能送就送(他们都是去往最高处途中顺手的事),然后按照r降序送,这样保证了最高不会再来,不会有浪费,途中记录一下乘客在原序列的中的位置最后输出即可
代码实现
#include <bits/stdc++.h>using i64 = long long;int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);int t;std::cin >> t;while (t--) {int n, f;std::cin >> n >> f;std::vector<std::array<int, 3>> lr(n);for (int i = 0; i < n; i++) {std::cin >> lr[i][0] >> lr[i][1];lr[i][2] = i + 1;}std::sort(lr.begin(), lr.end());i64 ans = 0;std::vector<int> ord, F(n);for (int i = 0; i < n; i++) {auto [l, r, idx] = lr[i];if (l < f) {if (r > f) {f = r;ans += r - l;ord.push_back(idx);F[idx - 1] = 1;}continue;}if (l > f) {ans += l - f;}f = r;ans += r - l;ord.push_back(idx);F[idx - 1] = 1;}std::sort(lr.begin(), lr.end(), [&](std::array<int, 3> a, std::array<int, 3> b) { return a[0] > b[0]; });for (int i = 0; i < n; i++) {auto [l, r, idx] = lr[i];if (F[idx - 1]) {continue;}f = r;ans += r - l;ord.push_back(idx);F[idx - 1] = 1;}std::cout << ans << "\n";for (int i = 0; i < n; i++) {std::cout << ord[i] << " \n"[i == n - 1];}}
}
H. Heavy-light Decomposition
题目大意
给你几条链,问能否构造出一棵树,让它HLD的结果是这几条链
解题思路
乱搞一下发现不可能的情况有两种,链的长度全相等或者至少有两条最长链,链的长度极差是1(证明)。
剩下的情况里,如果只有一条链直接输出即可;如果最长链只有一条,其他链挂最长链第一个节点即可;如果有多条最长链,最短链挂最长链第二个节点,其余链挂最长链第一个节点即可
代码实现
#include <bits/stdc++.h>int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);int t;std::cin >> t;while (t--) {int n, k, maxn = 0, minn = 1e9, cnt = 0, idx = -1;std::cin >> n >> k;std::vector<int> len(k);std::vector<std::array<int, 2>> lr(k);for (int i = 0; i < k; i++) {std::cin >> lr[i][0] >> lr[i][1];len[i] = lr[i][1] - lr[i][0] + 1;if (len[i] > maxn) {idx = i;}if (maxn == len[i]) {cnt++;} else if (maxn < len[i]) {maxn = len[i];cnt = 1;}minn = std::min(minn, len[i]);}if (maxn == minn && k >= 2 || maxn - minn == 1 && cnt >= 2) {std::cout << "IMPOSSIBLE\n";} else {std::vector<int> ans(n + 1);if (cnt == 1) {for (auto [l, r] : lr) {ans[l] = lr[idx][0];for (int i = l + 1; i <= r; i++) {ans[i] = i - 1;}}ans[lr[idx][0]] = 0;} else {ans[lr[idx][0]] = 0;for (int i = lr[idx][0] + 1; i <= lr[idx][1]; i++) {ans[i] = i - 1;}for (int i = 0; i < k; i++) {if (i != idx) {if (len[i] != minn) {ans[lr[i][0]] = lr[idx][0];for (int j = lr[i][0] + 1; j <= lr[i][1]; j++) {ans[j] = j - 1;}} else {ans[lr[i][0]] = lr[idx][0] + 1;for (int j = lr[i][0] + 1; j <= lr[i][1]; j++) {ans[j] = j - 1;}}}}}for (int i = 1; i <= n; i++) {std::cout << ans[i] << " \n"[i == n];}}}
}
M. Make It Divisible
题目大意
给你一个数组,问每个数都加上x后满足相邻数字互为倍数的x有多少个并求和
解题思路
先用单调栈找到所有bi和它两侧第一个比它大的数构成多个AB数对,接下来挑选x让所有AB数对成为倍数关系,只需要枚举任意一个数对差值的fac,找出构成所有数对都为倍数关系的fac统计即可
代码实现
#include <bits/stdc++.h>using i64 = long long;int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);int t;std::cin >> t;while (t--) {i64 n, k;std::cin >> n >> k;std::vector<int> b(n);for (int i = 0; i < n; i++) {std::cin >> b[i];}std::stack<int> stk;std::vector<std::array<int, 2>> P;for (int i = 0; i < n; i++) {while (!stk.empty() && b[stk.top()] >= b[i]) {if (b[stk.top()] > b[i]) {P.push_back({b[i], b[stk.top()]});}stk.pop();}stk.push(i);}while (!stk.empty()) {stk.pop();};for (int i = n - 1; i >= 0; i--) {while (!stk.empty() && b[stk.top()] >= b[i]) {if (b[stk.top()] > b[i]) {P.push_back({b[i], b[stk.top()]});}stk.pop();}stk.push(i);}if (P.empty()) {std::cout << k << " " << k * (k + 1) / 2 << "\n";continue;}std::vector<int> X;int A = P[0][1] - P[0][0];for (int i = 1; i * i <= A && i <= k + P[0][0]; i++) {if (A % i == 0) {if (i > P[0][0]) {X.push_back(i - P[0][0]);}if (A / i > i && A / i <= k + P[0][0] && A / i > P[0][0]) {X.push_back(A / i - P[0][0]);}}}std::vector<int> ans;for (auto x : X) {int f = 1;for (auto [A, B] : P) {if ((B + x) % (A + x) != 0) {f = 0;break;}}if (f) {ans.push_back(x);}}std::cout << ans.size() << " " << std::accumulate(ans.begin(), ans.end(), 0ll) << "\n";}
}