F. Mice and Holes
F. Mice and Holes
https://codeforces.com/problemset/problem/797/F
贪心排序+单调队列优化 DP
首先基于贪心,先把小球和洞都按坐标排序,最优策略必然按坐标从小到大的顺序放入小球到洞里。
然后观察数据范围,很容易想到 \(dp_{i,j}\) 表示考虑了前 \(i\) 个洞,已经放了 \(j\) 个球,转移两种情况:
- 这个洞完全不放球,\(dp_{i,j}=dp_{i-1,j}\)
- \(dp_{i,j}=\max_{k=j-c+1}^{j}(dp_{i-1,k-1}+sum(k,j))\),其中 \(sum(k,j)\) 表示第 \(i\) 个洞和 \([k,j]\) 的小球的距离之和,这种情况可以用前缀和,单调队列优化。
Code
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<int> x(n + 1);
std::vector<std::array<int, 2>> pc(m + 1);
for (int i = 1; i <= n; i++) {
std::cin >> x[i];
}
for (int i = 1; i <= m; i++) {
std::cin >> pc[i][0] >> pc[i][1];
}
std::sort(x.begin() + 1, x.end());
std::sort(pc.begin() + 1, pc.end());
constexpr i64 inf = 1e18;
std::vector<i64> dp(n + 1, inf);
dp[0] = 0;
for (int i = 1; i <= m; i++) {
std::vector<i64> ndp = dp;
std::vector<i64> s(n + 1, 0);
auto [p, c] = pc[i];
std::deque<int> que;
que.push_back(0);
for (int j = 1; j <= n; j++) {
s[j] = s[j - 1] + std::abs(p - x[j]);
while (que.size() && j - c > que.front()) que.pop_front();
ndp[j] = std::min(ndp[j], dp[que.front()] + s[j] - s[que.front()]);
while (que.size() && dp[que.back()] - s[que.back()] > dp[j] - s[j]) que.pop_back();
que.push_back(j);
}
dp.swap(ndp);
}
std::cout << (dp[n] == inf ? -1 : dp[n]) << '\n';
return 0;
}

浙公网安备 33010602011771号