CF 559E

题目大意

在一条 (,+) 的数轴上,有 N 盏探照灯,坐标分别为ai。每盏探照灯都可以往负方向或正方向发射光线,但每盏灯都有一个强度 li ,也就是说他最多只能照到 (aili,ai) (ai,ai+li) 。问你,在合法的规划每盏灯的方向下,最多能照到多少长度的数轴。一段数轴 (l,r) 的长度为 rl ,他被照到当且仅当整段都被某些探照灯所覆盖。

数据范围

N100,ai,li108

题解

我们先将探照灯按 ai 排序。
首先要注意,假如一段区间 (l,r) 被覆盖了,那么必然是被一段连续的探照灯 ([i,j] 所覆盖的。
Fi,j,k 表示当前用了前 i 盏灯,最后一段是探照灯j贡献的,其方向为 k 最多能照到多少长度。当k=0时表示照向负方向, k=1 时表示照向正方向。
假设我们已经知道了 Fi,j,k ,接着要进行转移。
Pre 表示当前覆盖区间的右端点,可以直接用 aj+klj 计算出来。我们尝试枚举一个 p ,表示要把前p盏灯用完,并且 p 要对答案有贡献,也就是说,在最终的方案中,p能唯一(或称为最先)覆盖某一段灯。而且 p 枚举时应当两个方向都枚举。
那么我们可以画一幅图,
这里写图片描述
Pre就是之前的灯照的区间, Far 表示当前转移枚举的右端点,那么有用的 P 就如图中的P1,P2所示,必须要把某一段 Pre,Far 之间的空白填补。设 P 的右端点为Nr。那么 P 造成的贡献就是min(Lp,NrPre),最后再考虑上 Far,P1 之间的覆盖, P 的贡献就是min(Lp,NrPre)+FarNr。因此,这种转移是
Fp,far,dir=Fi,j,k+min(Lp,NrPre)+FarNr

这里也体现了我们一开始将灯按 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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值