1 条题解
-
0
题解
设 ,正数表示多余的土,负数表示缺土。把所有正值按下标记录为供给点,负值为需求点。运输单位成本为 ,但你也可以选择“挖掉再买”的替代方案,成本恒为 ,因此实际在两点间搬运一单位的最优成本为
$$\\operatorname{cost}(i,j)=\\min\\bigl(z\\cdot|i-j|,\,x+y\\bigr). $$多余/缺少的总量不一定相等:若 ,剩余的土只能挖掉,花费 ;若 ,缺的土只能购买,花费 。先把这一部分加入答案,其余部分则在供给点与需求点之间配对搬运。
由于搬运成本关于下标的绝对值函数满足一维最优匹配的单调性,按下标从左到右贪心配对即可得到最小费用:用两个指针遍历供给列表和需求列表,每次输送
flow=min(surplus, deficit),累加flow * min(z * distance, x + y),消耗掉一方就移动相应指针。复杂度
- 时间:,每个位置至多入队出队一次。
- 空间:。
参考实现
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; long long x, y, z; if (!(cin >> N >> x >> y >> z)) return 0; vector<long long> A(N + 1), B(N + 1); for (int i = 1; i <= N; ++i) cin >> A[i] >> B[i]; struct Node { int pos; long long amt; }; vector<Node> sur, def; long long sumSur = 0, sumDef = 0; for (int i = 1; i <= N; ++i) { long long d = A[i] - B[i]; if (d > 0) { sur.push_back({i, d}); sumSur += d; } else if (d < 0) { def.push_back({i, -d}); sumDef += -d; } } long long ans = 0; if (sumSur > sumDef) ans += (sumSur - sumDef) * y; // 多余的挖掉 else ans += (sumDef - sumSur) * x; // 不足的买土 size_t i = 0, j = 0; while (i < sur.size() && j < def.size()) { long long flow = min(sur[i].amt, def[j].amt); long long dist = llabs((long long)sur[i].pos - def[j].pos); long long costPer = min(z * dist, x + y); ans += flow * costPer; sur[i].amt -= flow; def[j].amt -= flow; if (sur[i].amt == 0) ++i; if (def[j].amt == 0) ++j; } cout << ans << '\n'; return 0; }
- 1
信息
- ID
- 5722
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者