ICPC 2024 杭州站
A. AUS
题目大意
给你三个字符串S1、S2、S3,问是否存在一种字母映射方式使得F(S1)等于F(S2)但是不等于F(S3)
解题思路
想要让S1、S2相等首先显然要满足长度相等,因此可以先把长度不相等的时候的存在关系判断出来,对于三个字符串长度都相等的情况,可以通过遍历修改字符串让S1变成S2,或者S2变成S1,逐字符比较不相等修改即可,可直接使用Python的replace完成替换,注意要提前把字符取出来,因为replace后字符串已经发生变化,最后只需要查看是不是满足题目要求即可
代码实现
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取大,即至少操作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降序送,这样保证了当前这个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";
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具