专栏文章
CF797F Mice and Holes 题解
CF797F题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min11o82
- 此快照首次捕获于
- 2025/12/01 18:49 3 个月前
- 此快照最后确认于
- 2025/12/01 18:49 3 个月前
首先根据贪心的思想可知,如果老鼠 在老鼠 的左边,那么对应钻进的洞 也应该在 的左边。因为如果出现了老鼠与洞连线彼此交叉的情况,则可以调整为不交叉的选择方式,显然不劣于原情况。所以如果老鼠按照位置排序,它们钻进的洞也应该是按照位置排序的,那么可以根据这个性质动态规划。
设 表示前 个洞里有前 只老鼠的最小代价,如果枚举前 个老鼠在前 个洞里,那么有转移方程 ,其中 表示 号洞与第 号老鼠之间的距离,可以用前缀和来优化求和到 。优化后总时间复杂度量级为 ,默认 与 同阶,显然会超时。
考虑如何优化。设 表示到第 个洞的前 个老鼠的距离和,那么上述转移方程转化为 ,显然 与 无关,因此可以提出,那么转移方程变形为 ,括号内的可以通过单调队列来实现,可以做到均摊 查询。单调队列优化后的总时间复杂度量级为 。
CPP#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
int x[5005];
pair<int,int> p[5005];
int cnt[5005],sum[5005];
int dp[5005][5005];
int q[5005];
signed main(){
memset(dp,0x3f,sizeof(dp));
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> x[i];
}
for(int i=1;i<=m;i++){
cin >> p[i].first >> p[i].second;
}
sort(x + 1,x + n + 1);
sort(p + 1,p + m + 1);
for(int i=1;i<=m;i++){
sum[i] = sum[i - 1] + p[i].second;
}
if(sum[m] < n){
cout << -1;
return 0;
}
for(int i=0;i<=m;i++){
dp[i][0] = 0;
}
for(int i=1;i<=m;i++){
int l = 0,r = 0;
q[++ r] = 0;
for(int j=1;j<=min(sum[i],n);j++){
cnt[j] = cnt[j - 1] + abs(p[i].first - x[j]);
dp[i][j] = dp[i - 1][j];
while(l <= r && j - q[l] > p[i].second) l ++;
while(l <= r && dp[i - 1][q[l]] - cnt[q[l]] > dp[i - 1][j] - cnt[j]) l ++;
q[++ r] = j;
if(l <= r) dp[i][j] = min(dp[i][j],dp[i - 1][q[l]] - cnt[q[l]] + cnt[j]);
}
}
cout << dp[m][n];
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...