题目大意
在一条
(−∞,+∞)
的数轴上,有
N
盏探照灯,坐标分别为
数据范围
N≤100,ai,li≤108
题解
我们先将探照灯按
ai
排序。
首先要注意,假如一段区间
(l,r)
被覆盖了,那么必然是被一段连续的探照灯
([i,j]
所覆盖的。
设
Fi,j,k
表示当前用了前
i
盏灯,最后一段是探照灯
假设我们已经知道了
Fi,j,k
,接着要进行转移。
设
Pre
表示当前覆盖区间的右端点,可以直接用
aj+k∗lj
计算出来。我们尝试枚举一个
p
,表示要把前
那么我们可以画一幅图,
Fp,far,dir=Fi,j,k+min(Lp,Nr−Pre)+Far−Nr
。
这里也体现了我们一开始将灯按
ai
排序的优势。我们的枚举是单调的,而且我们可以轻松解决这种情况
最后我们可以得到一个 O(N3) 的算法。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 105;
struct Node
{
int x,l;
}A[MAXN];
int F[MAXN][MAXN][2],N,Ans;
bool cmp(Node a,Node b) {return a.x < b.x;}
int main()
{
//freopen("data.in","r",stdin),freopen("data.out","w",stdout);
scanf("%d", &N);
for(int i = 1;i <= N;i ++) scanf("%d%d", &A[i].x, &A[i].l);
sort(A + 1,A + N + 1,cmp);
A[0].x = -(1 << 30);
for(int i = 0;i <= N;i ++)
for(int j = 0;j <= i;j ++)
for(int p = 0;p < 2;p ++)
{
Ans = max(Ans,F[i][j][p]);
int Pr = A[j].x + p * A[j].l;
for(int k = i + 1,mx = -(1 << 30),a,b;k <= N;k ++)
for(int d = 0;d < 2;d ++)
{
int nxt = A[k].x + d * A[k].l;
if (nxt > mx) mx = nxt,a = k,b = d;
F[k][a][b] = max(F[k][a][b],F[i][j][p] + min(A[k].l,nxt - Pr) + mx - nxt);
}
}
printf("%d\n", Ans);
return 0;
}