Codeforces Round 980 Div. 2 题解分析
A 题:基础数值计算
本题考察简单的条件判断与方程求解。给定两个整数,需根据大小关系决定输出策略。
核心逻辑:当第二个数不超过第一个数时,直接返回第一个数;否则通过方程推导,结果为 2*a - b 与 0 的较大值。
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int tc;
cin >> tc;
while (tc--) {
long long p, q;
cin >> p >> q;
if (p >= q) {
cout << p << '\n';
} else {
cout << max(2LL * p - q, 0LL) << '\n';
}
}
return 0;
}
B 题:贪心策略与累计消耗
问题可转化为:将数组升序排列后,模拟逐层消耗资源的过程。每次将当前层所有元素提升至同一高度,计算所需代价。
关键观察:排序后,第 i 个元素与第 i-1 个元素的高度差,需要作用于后续 n-i+1 个元素。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int cases;
cin >> cases;
while (cases--) {
int m;
ll remain;
cin >> m >> remain;
vector<ll> h(m);
for (auto &x : h) cin >> x;
sort(h.begin(), h.end());
ll res = 0, prev = 0;
for (int i = 0; i < m; i++) {
ll need = (h[i] - prev) * (m - i);
res++;
if (remain <= need) {
res += remain;
remain = 0;
break;
}
remain -= need;
res += need;
prev = h[i];
}
cout << res - 1 << '\n';
}
return 0;
}
C 题:数对排序规则设计
需要为数对定义一种全序关系,使得按此顺序连接后满足特定条件。通过分析数对的包含关系,可确定排序关键字。
排序策略:以数对的最小值为首要关键字,最大值为次要关键字升序排列。这样可保证若一个数对完全"支配"另一个,则前者排在前面。
#include <bits/stdc++.h>
using namespace std;
struct PairInfo {
int first, second;
int lo, hi;
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int cases;
cin >> cases;
while (cases--) {
int n;
cin >> n;
vector<PairInfo> arr(n);
for (auto &it : arr) {
cin >> it.first >> it.second;
it.lo = min(it.first, it.second);
it.hi = max(it.first, it.second);
}
sort(arr.begin(), arr.end(), [](const PairInfo &x, const PairInfo &y) {
if (x.lo != y.lo) return x.lo < y.lo;
return x.hi < y.hi;
});
for (const auto &it : arr) {
cout << it.first << ' ' << it.second << ' ';
}
cout << '\n';
}
return 0;
}
D 题:图论建模与最短路
将跳跃过程抽象为带权有向图,通过最短路算法求解最优策略。每个位置有两种转移方式:向左移动无代价,或跳跃到指定位置但损失当前分数。
算法思路:从起点运行 Dijkstra 算法,得到到达每个位置的最小损失。最终答案为前缀和减去对应位置的最短路距离的最大值。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using Edge = pair<ll, int>;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int cases;
cin >> cases;
while (cases--) {
int n;
cin >> n;
vector<ll> score(n), jump(n);
for (auto &x : score) cin >> x;
for (auto &x : jump) cin >> x;
vector<vector<Edge>> graph(n);
for (int i = 0; i < n; i++) {
if (i > 0) graph[i].push_back({0, i - 1});
graph[i].push_back({score[i], jump[i] - 1});
}
const ll INF = 1e18;
vector<ll> dist(n, INF);
vector<bool> seen(n, false);
priority_queue<Edge, vector<Edge>, greater<>> pq;
dist[0] = 0;
pq.push({0, 0});
while (!pq.empty()) {
auto [d, u] = pq.top(); pq.pop();
if (seen[u]) continue;
seen[u] = true;
for (auto [w, v] : graph[u]) {
if (dist[v] > d + w) {
dist[v] = d + w;
pq.push({dist[v], v});
}
}
}
ll pref = 0, best = 0;
for (int i = 0; i < n; i++) {
pref += score[i];
best = max(best, pref - dist[i]);
}
cout << best << '\n';
}
return 0;
}