题目链接:https://www.acwing.com/problem/content/description/3773/
题目大意:按照题目要求消灭两种类型怪兽(可以消耗 c 转换)的最小消耗。
解题思路:循环记录 0 和 1 出现的次数,消灭一个 0 的最小消耗为 min(a, b+c)
,消灭一个 1 的最小消耗为 min(a+c, b)
。
示例程序:
#include <bits/stdc++.h> using namespace std; int T, n, a, b, c, c0, c1; char s[1010]; int main() { cin >> T; while (T--) { cin >> n >> a >> b >> c >> s; c0 = c1 = 0; for (int i = 0; i < n; i++) (s[i] == '0') ? c0++ : c1++; cout << c0 * min(a, b+c) + c1 * min(a+c, b) << endl; } return 0; }
题目链接:https://www.acwing.com/problem/content/3774/
题目大意:从数列里面选出一些数满足 \(a_i - a_j = i - j\)。
解题思路:将所有 \(a_i\) 放入 \(a_i - i\) 的桶中(实际实现时用的 map),找最大的那个桶。
示例程序:
#include <bits/stdc++.h> using namespace std; map<int, long long> mp; int n, a; long long ans; int main() { cin >> n; for (int i = 0; i < n; i++) { cin >> a; mp[a-i] += a; } for (auto p : mp) ans = max(ans, p.second); cout << ans << endl; return 0; }
题目链接:https://www.acwing.com/problem/content/3775/
题目大意:求一条路径走过来最短路最少和最多更新次数。
解题思路:返图+最短路+最短路计数。最少更新次数是不是最短路径的点,最多更新次数是:不是最短路径的点+最短路径不唯一的点。由于边权为 \(1\),所以可以 bfs 求最短路。注意:强连通图的条件很重要,这能保证反图也强连通。
最主要的逻辑在第 40 ~ 42 行。请认真体会(调了好长时间)
示例程序:
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; int n, m, k, p[maxn], dis[maxn], cnt[maxn], pre[maxn]; vector<int> g[maxn]; queue<int> que; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n >> m; while (m--) { int u, v; cin >> u >> v; g[v].push_back(u); // 建反图 } cin >> k; for (int i = 1; i <= k; i++) cin >> p[i]; memset(dis, -1, sizeof(int)*(n+1)); dis[p[k]] = 0; cnt[p[k]] = 1; que.push(p[k]); while (!que.empty()) { int u = que.front(); que.pop(); for (auto v : g[u]) { if (dis[v] == -1) { dis[v] = dis[u] + 1; cnt[v] = 1; pre[v] = u; que.push(v); } else if (dis[v] == dis[u] + 1) cnt[v]++; } } int c1 = 0, c2 = 0; for (int i = 1; i <= k; i++) { int u = p[i]; if (i < k && cnt[u]==1 && pre[u] == p[i+1]) continue; // 新增条件:非最短路但是不唯一也不更新 if (i < k && dis[u] != dis[p[i+1]] + 1) c1++; if (cnt[u] > 1 || i < k && pre[u] != p[i+1]) c2++; } cout << c1 << " " << c2 << endl; return 0; }