Careful Thief (区间和最大)

原题Gym - 101810A

题意

有条1——1e9的坐标轴,给出n给区间l,r,v表示l到r范围内的点价值为v
你可以得到连续的一段区间的价值,区间最长为k,求可以得到的最大值

解析:

相当于在长度固定的情况下移动区间,有以下结论

  • 选取区间的端点一定是某个给出的区间的端点,因为如果两端都在某个区间的中间话,往左或往右一定可以做到单调不减

所以,我们可以扫一遍所有区间的端点,使之为我们选取区间的端点

接下来就是实现和优化了


因为是一维坐标轴且需要得出的答案是一段连续区间,所以可以参考尺取法来实现,在左端点往后移动的时候,维护nowans,删去前面段的价值,加进后面段的价值,ans取个max就行

然后以右端点的时候只要转化一下端点值,再套上面的方法做一遍就行

代码:


struct node{
    int l,r,v;
    bool operator < (const node a)const{
        return l<a.l;
    }
    void init(){
        scanf("%d%d%d",&l,&r,&v);
    }
}e[100009];


int main(){
    int t=read();
    while(t--){
        int n=read(),k=read();
        for(int i=1;i<=n;i++)e[i].init();
        sort(e+1,e+1+n);

////////////////以左端点开始
        e[0].l=e[1].l-k;//为了移动r
        e[0].r=e[1].l-1;
        e[0].v=0;

        D ans=0,nowans=0;
        int r=e[1].l-1,ar=0;//当前的右界为r,且右界在第ar段的前面或里面
        for(int i=1;i<=n;i++){
            nowans-=(D)(e[i-1].r-e[i-1].l+1)*e[i-1].v;
            int tmpr=r+e[i].l-e[i-1].l;
            while(1){
                if(ar>n)break;
                if(tmpr<e[ar].l)break;
                if(tmpr>=e[ar].l&&tmpr<=e[ar].r){
                    nowans+=(D)(tmpr-max(r+1,e[ar].l)+1)*e[ar].v;
                    break;
                }
                else{
                    nowans+=(D)(e[ar].r-max(r+1,e[ar].l)+1)*e[ar].v;
                    ar++;
                }
            }

            r=tmpr;
            ans=max(ans,nowans);
        }

////////////////以右端点开始
        for(int i=1;i<=n;i++){
            e[i].l=1000000000-e[i].l+1;
            e[i].r=1000000000-e[i].r+1;
            swap(e[i].l,e[i].r);
        }
        for(int i=1;i<=n/2;i++)swap(e[i],e[n-i+1]);
        e[0].l=e[1].l-k;
        e[0].r=e[1].l-1;
        e[0].v=0;
        nowans=0;
        r=e[1].l-1,ar=0;
        for(int i=1;i<=n;i++){
            nowans-=(D)(e[i-1].r-e[i-1].l+1)*e[i-1].v;
            int tmpr=r+e[i].l-e[i-1].l;
            while(1){
                if(ar>n)break;
                if(tmpr<e[ar].l)break;
                if(tmpr>=e[ar].l&&tmpr<=e[ar].r){
                    nowans+=(D)(tmpr-max(r+1,e[ar].l)+1)*e[ar].v;
                    break;
                }
                else{
                    nowans+=(D)(e[ar].r-max(r+1,e[ar].l)+1)*e[ar].v;
                    ar++;
                }
            }
            r=tmpr;
            ans=max(ans,nowans);
        }
////////
       printf("%lld\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值