题意:
给一段长度为m的线段,线段上有n个路灯,
每个路灯在位置
x
i
x_i
xi且能照亮范围
[
x
i
−
s
i
,
x
i
+
s
i
]
[x_i-s_i,x_i+s_i]
[xi−si,xi+si]
我们可以花费一个硬币使得某个路灯的
s
i
s_i
si的增大1,可以操作任意多次
求能使区间[1,m]被路灯照亮的最小硬币花费
思路:
dp[i]表示线段 [ 1 , i ] [1,i] [1,i]被覆盖所需的最小代价
第一层循环dp从1到m,第二层循环遍历n个路灯,维护dp
时间复杂度O(n*m)
状态转移分析:
-
x [ j ] < = i x[j]<=i x[j]<=i:路灯在当前位置的左边的时候
-
x
[
j
]
+
s
[
j
]
>
=
i
x[j]+s[j]>=i
x[j]+s[j]>=i:第
j
j
j个路灯可以照亮位置
i
i
i
d p [ i ] = m i n ( d p [ i ] , d p [ m a x ( 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
]
<
i
x[j]+s[j]<i
x[j]+s[j]<i:第
j
j
j个路灯照不到位置
i
i
i,需要扩展
s
[
j
]
s[j]
s[j]
d p [ i ] = m i n ( d p [ i ] , d p [ m a x ( 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
]
>
=
i
x[j]+s[j]>=i
x[j]+s[j]>=i:第
j
j
j个路灯可以照亮位置
i
i
i
-
x [ j ] > i x[j]>i x[j]>i:路灯在当前位置的右边的时候
-
x
[
j
]
−
s
[
j
]
<
=
i
x[j]-s[j]<=i
x[j]−s[j]<=i:第
j
j
j个路灯可以照亮位置
i
i
i
d p [ i ] = m i n ( d p [ i ] , d p [ m a x ( 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
]
>
i
x[j]-s[j]>i
x[j]−s[j]>i:第
j
j
j个路灯不能照亮位置
i
i
i
不用扩展
-
x
[
j
]
−
s
[
j
]
<
=
i
x[j]-s[j]<=i
x[j]−s[j]<=i:第
j
j
j个路灯可以照亮位置
i
i
i
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;
}