给定若n个区间,每次操作可以使一个区间左右拓宽1,求最小操作次数使得区间[1,m]均被覆盖.
考虑dp:
dp[i]=区间[i,m]均被覆盖的最小花费
转移:
d p [ i ] = d p [ i + 1 ] dp[i]=dp[i+1] dp[i]=dp[i+1],如果 [ 1 , i ] [1,i] [1,i]被原始区间覆盖.
否则, p = l − i , d p [ i ] = m i n ( p + d p [ r + p + 1 ] ) , ( l > = i ) p=l-i,dp[i]=min(p+dp[r+p+1]),(l>=i) p=l−i,dp[i]=min(p+dp[r+p+1]),(l>=i)
(当r+p+1>m时,令小标为m+1,即如果[l,r]区间拓宽至i,而右区间此时已经超过了m,该操作的代价就只有p)
所以,初始化 d p [ m + 1 ] = 0 , d p [ i ] = m − i + 1 dp[m+1]=0,dp[i]=m-i+1 dp[m+1]=0,dp[i]=m−i+1(可能花费最大值)
答案就是dp[1]
#include
using namespace std;
char buf[1<<20],*P1=buf,*P2=buf;
#define gc() (P1==P2&&(P2=(P1=buf)+fread(buf,1,1<<20,stdin),P1==P2)?EOF:*P1++)
#define TT templateinline
TT bool read(T &x){
x=0;char c=gc();bool f=0;
while(c<48||c>57){if(c==EOF)return 0;f^=(c=='-'),c=gc();}
while(47<c&&c<58)x=(x<<3)+(x<<1)+(c^48),c=gc();
if(f)x=-x;
return 1;
}
TT bool read(T&a,T&b){return read(a)&&read(b);}
TT bool read(T&a,T&b,T&c){return read(a)&&read(b)&&read(c);}
typedef long long ll;
const ll MAXN=2e5+8,mod=1e9+8,inf=0x3f3f3f3f;
#define lowbit(x) (x&(-x))
struct Node{int x,s;}a[88];
int n,m,dp[MAXN];
int main() {
read(n,m);
for(int i=0;i<n;++i)read(a[i].x,a[i].s);
for(int i=m;i>=0;--i){
int flag=0;
for(int j=0;j<n;++j){//i是否被覆盖
if(a[j].x-a[j].s<=i&&i<=a[j].x+a[j].s){
dp[i]=dp[i+1];
flag=1;
break;
}
}
if(flag)continue;
dp[i]=m-i+1;
for(int j=0;j<n;++j){
if(a[j].x-a[j].s>=i){
int p=a[j].x-a[j].s-i;
dp[i]=min(dp[i],p+dp[min(a[j].x+a[j].s+1+p,m+1)]);
//a[j].x+a[j].s该点已经覆盖了,所以要+1
}
}
}
printf("%d",dp[1]);
return 0;
}