首先我们要注意到一个事情
如果一个灯塔向左覆盖,那么比他小的某个灯塔如果向左覆盖的端点大于当前塔向左覆盖的端点,他一定向右覆盖
对于当前灯塔向右覆盖也是同理
那么我们只需要记录当前覆盖到的端点就可以完成转移了
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #include<vector> using namespace std; typedef long long LL; const int maxn=310; const LL oo=1LL<<62; int n,m,a[maxn],b[maxn],p[maxn],L[maxn],R[maxn]; LL dp[maxn][maxn][maxn],ans; vector<int>V; void cmax(LL &a,LL b){if(a<b)a=b;} int main(){ scanf("%d",&n); for(int i=0;i<n;++i){ scanf("%d%d",&a[i],&b[i]); V.push_back(a[i]);V.push_back(a[i]+b[i]);V.push_back(a[i]-b[i]); } sort(V.begin(),V.end()); V.erase(unique(V.begin(),V.end()),V.end()); for(int i=0;i<n;++i){ p[i]=lower_bound(V.begin(),V.end(),a[i])-V.begin(); L[i]=lower_bound(V.begin(),V.end(),a[i]-b[i])-V.begin(); R[i]=lower_bound(V.begin(),V.end(),a[i]+b[i])-V.begin(); } m=V.size(); for(int i=0;i<m;++i){ for(int j=0;j<m;++j){ for(int k=0;k<m;++k){ dp[i][j][k]=-oo; } } } for(int i=0;i<m;++i)dp[0][0][i]=0; for(int i=0;i<m-1;++i){ int pos=-1; for(int j=0;j<n;++j)if(p[j]==i)pos=j; for(int j=0;j<m;++j){ for(int k=0;k<m;++k){ if(dp[i][j][k]>=0){ if(pos==-1){ cmax(dp[i+1][j][k],dp[i][j][k]+(j>=i+1||k<=i?(V[i+1]-V[i]):0)); }else{ cmax(dp[i+1][max(j,R[pos])][k],dp[i][j][k]+V[i+1]-V[i]); if(k==L[pos]){ for(int l=k;l<m;++l)cmax(dp[i+1][max(j,i)][l],dp[i][j][k]+(j>=i+1||l<=i?(V[i+1]-V[i]):0)); } } } } } } ans=0; for(int i=0;i<m;++i)cmax(ans,dp[m-1][i][m-1]); printf("%I64d ",ans); return 0; }