题意
n n n个广播,每个广播的范围可以通过一个花费扩大 1 1 1,求最小花费覆盖。
题解
d
p
dp
dp
首先我们可考虑倒着
d
p
dp
dp,正着也行。
d
p
[
i
]
dp[i]
dp[i]表示覆盖
i
→
m
i \to m
i→m的最小花费。
1.如果当前已经被覆盖,显然答案是
d
p
[
i
]
=
d
p
[
i
+
1
]
dp[i]=dp[i+1]
dp[i]=dp[i+1]
2.如果在某个广播中心左侧,答案是
d
p
[
i
]
=
d
p
[
L
[
j
]
−
i
+
R
[
i
]
+
1
]
+
L
[
j
]
−
i
dp[i]=dp[L[j]-i+R[i]+1]+L[j]-i
dp[i]=dp[L[j]−i+R[i]+1]+L[j]−i
【当然下标有可能超过
m
m
m,取最小值即可。
3.如果在右侧显然没有任何意义,因为接下来我们干的事会完全涵盖这种情况(反之却不可以)。
但是我们可以发现这样有一个弊端,就是比如,
d
p
[
3
]
=
5
dp[3]=5
dp[3]=5,
d
p
[
4
]
=
i
n
f
dp[4]=inf
dp[4]=inf
但是显然
d
p
[
4
]
=
d
p
[
3
]
dp[4]=dp[3]
dp[4]=dp[3]是没有任何问题的。
所以我们可以采取,线段树来维护最小值,情况二 d p [ i ] = d p [ x ] + k dp[i]=dp[x]+k dp[i]=dp[x]+k, d p [ x ] dp[x] dp[x]直接求很有可能是 i n f inf inf,见上述例子,所以访问 m i n d p [ i ≥ x ] mindp[i \geq x] mindp[i≥x],即可。
或者采用比较神仙的一种做法,能够保证复杂度在
n
m
nm
nm
首先我们
≤
0
o
r
≥
m
+
1
\leq0or\geq m+1
≤0or≥m+1处放多少个广播绝对不会影响最后结果,因为他们导致的最优结果只能是
m
m
m,而里面的广播最坏结果是
m
−
1
m-1
m−1。
但是设置一个 m + 1 m+1 m+1处的广播有什么好处呢,我们再考虑刚刚那个例子,显然 d p [ i ] = m − i + 1 dp[i]=m-i+1 dp[i]=m−i+1(根据这个广播),正好能够处理这种情况。因为刚好加上这部分差等价于直接覆盖到底。
那再往前推也会有类似的例子,并且不只是加到底这么简单了,而可能加到下一个广播的最优区域外,这个时候前面的最优情况还没有迭代到,就需要借用下一个的来补上(实际想表达的是由前面的加过来,但是可以用后一个补上来保证复杂度。并且贡献是等价的。)
举个例子。两个广播
[
3
,
0
]
,
[
7
,
0
]
[3,0],[7,0]
[3,0],[7,0],
m
=
9
m=9
m=9
显然
d
p
[
5
]
=
2
dp[5]=2
dp[5]=2,如果按之前后面,大于
5
5
5的都是
i
n
f
inf
inf,但实际上他们也应该是2。这里我有一个更大的广播比如
[
4
,
0
]
[4,0]
[4,0],忽略
[
3
,
0
]
[3,0]
[3,0],处理到
d
p
[
1
]
=
d
p
[
8
]
+
3
dp[1]=dp[8]+3
dp[1]=dp[8]+3,
d
p
[
8
]
dp[8]
dp[8]应该是多少呢,显然应该是
1
1
1而不是
2
2
2,看起来是之前构成的,其实是
4
4
4这个广播继续扩大了一下。
回过头来考虑
3
3
3,
d
p
[
1
]
=
d
p
[
6
]
+
2
=
d
p
[
8
]
+
3
=
1
+
3
=
4
dp[1]=dp[6]+2=dp[8]+3=1+3=4
dp[1]=dp[6]+2=dp[8]+3=1+3=4,
当然忽略
3
3
3,加入一个
[
2
,
0
]
[2,0]
[2,0],
d
p
[
1
]
=
d
p
[
4
]
+
1
dp[1]=dp[4]+1
dp[1]=dp[4]+1,这个
4
4
4位置如何处理呢,显然是
d
p
[
4
]
=
d
p
[
10
]
+
3
dp[4]=dp[10]+3
dp[4]=dp[10]+3
如果前面的位置更大点,最后理应是
2
2
2的这个广播扩大这么大,但是计算
4
4
4的时候是以
7
7
7扩大这么大计算的,不过可以直接继承过去,等价于先从那里借的。以后还回去。
没试过数据结构,不过貌似 n 2 m n^2m n2m都能过,直接数据结构可能更方便。
#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define sf(x) scanf("%d",&x)
using namespace std;
const int maxn = 2e5+500;
typedef long long ll;
int n,m;
int dp[maxn];
int L[maxn],R[maxn];
int main(){
cin>>n>>m;
FOR(i,1,n){
int x,s;
sf(x),sf(s);
L[i]=max(1,x-s);
R[i]=min(x+s,m);
}
memset(dp,0x3f,sizeof(dp));
dp[m+1]=0;
for(int i=1;i<=m;i++)dp[i]=m-i+1;
for(int i=m;i>=1;i--){
for(int j=1;j<=n;j++){
if(L[j]<=i&&i<=R[j]){
dp[i]=min(dp[i],dp[i+1]);
}
else if(i<L[j]){
dp[i]=min(dp[i],dp[min(R[j]+L[j]-i,m)+1]+L[j]-i);
}
}
}
cout<<dp[1]<<endl;
}