F. Mice and Holes

F. Mice and Holes

https://codeforces.com/problemset/problem/797/F

贪心排序+单调队列优化 DP

首先基于贪心,先把小球和洞都按坐标排序,最优策略必然按坐标从小到大的顺序放入小球到洞里。

然后观察数据范围,很容易想到 \(dp_{i,j}\) 表示考虑了前 \(i\) 个洞,已经放了 \(j\) 个球,转移两种情况:

  1. 这个洞完全不放球,\(dp_{i,j}=dp_{i-1,j}\)
  2. \(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;
}

posted @ 2024-06-29 02:51  jackle  阅读(22)  评论(0)    收藏  举报