
题意:
给一段长度为m的线段,线段上有n个路灯,
每个路灯在位置xix_ixi且能照亮范围[xi−si,xi+si][x_i-s_i,x_i+s_i][xi−si,xi+si]
我们可以花费一个硬币使得某个路灯的sis_isi的增大1,可以操作任意多次
求能使区间[1,m]被路灯照亮的最小硬币花费
思路:
dp[i]表示线段[1,i][1,i][1,i]被覆盖所需的最小代价
第一层循环dp从1到m,第二层循环遍历n个路灯,维护dp
时间复杂度O(n*m)
状态转移分析:
-
x[j]<=ix[j]<=ix[j]<=i:路灯在当前位置的左边的时候
- x[j]+s[j]>=ix[j]+s[j]>=ix[j]+s[j]>=i:第jjj个路灯可以照亮位置iii
dp[i]=min(dp[i],dp[max(0,x[j]−s[j]−1)])dp[i]=min(dp[i],dp[max(0,x[j]-s[j]-1)])dp[i]=min(dp[i],dp[max(0,x[j]−s[j]−1)]) - x[j]+s[j]<ix[j]+s[j]<ix[j]+s[j]<i:第jjj个路灯照不到位置iii,需要扩展s[j]s[j]s[j]
dp[i]=min(dp[i],dp[max(0,2∗x[j]−i−1)]+(i−x[j]−s[j]))dp[i]=min(dp[i],dp[max(0,2*x[j]-i-1)]+(i-x[j]-s[j]))dp[i]=min(dp[i],dp[max(0,2∗x[j]−i−1)]+(i−x[j]−s[j]))
- x[j]+s[j]>=ix[j]+s[j]>=ix[j]+s[j]>=i:第jjj个路灯可以照亮位置iii
-
x[j]>ix[j]>ix[j]>i:路灯在当前位置的右边的时候
- x[j]−s[j]<=ix[j]-s[j]<=ix[j]−s[j]<=i:第jjj个路灯可以照亮位置iii
dp[i]=min(dp[i],dp[max(0,x[j]−s[j]−1)])dp[i]=min(dp[i],dp[max(0,x[j]-s[j]-1)])dp[i]=min(dp[i],dp[max(0,x[j]−s[j]−1)]) - x[j]−s[j]>ix[j]-s[j]>ix[j]−s[j]>i:第jjj个路灯不能照亮位置iii
不用扩展
- x[j]−s[j]<=ix[j]-s[j]<=ix[j]−s[j]<=i:第jjj个路灯可以照亮位置iii
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,x[maxn],s[maxn],dp[maxn];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>x[i]>>s[i];
for(int i=1;i<=m;i++) dp[i]=i;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(x[j]<=i)
dp[i]=min(dp[i],dp[max(0,min(2*x[j]-i-1,x[j]-s[j]-1))]+max(0,i-(x[j]+s[j])));
else
dp[i]=min(dp[i],dp[max(0,x[j]-s[j]-1)]);
}
}
cout<<dp[m]<<endl;
}
这篇博客探讨了一个线段覆盖问题,其中涉及到n个路灯在一条长度为m的线段上,每个路灯有自己的照明范围。问题目标是最小化扩展路灯照明范围以覆盖整个线段所需的硬币花费。博主通过动态规划的方法,使用dp[i]表示线段[1,i]被覆盖的最小代价,并详细阐述了状态转移方程。最后,提供了AC代码实现该算法,时间复杂度为O(n*m)。
690

被折叠的 条评论
为什么被折叠?



