codeforces 721E

题目大意

在一条数轴上,你要从0走到 L
其中有n个不相交可行区域。
你要选最多的长度为 p 的段,使得每一段都在可行区域内。
并且假如你现在取的段是[x,x+p],那么你下次取的段的起始点 start 要满足。
start=x+p startx+p+t .
问最多取多少段?

解题思路

fi 为走完第 i 个区间的最优值。
gi表示令 fi 取得最优解的最靠左的停止唱歌的位置.
li,ri 为第 i 个区间的两个端点。那么:

fi=maxgj+tri{fj+(rimax{li,gj+t})p}

gi=max{li,gk+t}+(rimax{li,gk+t})pp

假如 i k转移。

容易看出,因为区间不相交,所以 gi 单掉不减,决策满足单调性,我们用一个单调队列来维护。每次取出队首满 gj+tri 的状态,更新当前状态。如果当前状态优于历史最优解,入队。注意取出的最后一个满足 gj+tri 的状态还可以用来更新下一个状态,它不出队。

参考程序

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define maxn 100005
#define min(a,b) (((a) < (b)) ? a : b)
#define max(a,b) (((a) > (b)) ? a : b)
using namespace std;

int f[maxn],g[maxn];

int l,n,p,t;

int head,tail;

int ans;

int main(){
    scanf("%d%d%d%d",&l,&n,&p,&t);
    head=1;
    tail=1;
    f[tail]=0;
    g[tail]=-t;
    fo(i,1,n) {
        int x,y,ans1,ans2;
        scanf("%d%d",&x,&y);
        ans1=ans2=0;
        if (head>1) head--;
        while (head<=tail && g[head]+t<=y) {
            int nx=max(x,g[head]+t),ny=y;
            if (f[head]+(ny-nx)/p>ans1) {
                ans1=f[head]+(ny-nx)/p;
                ans2=nx+(ny-nx)/p*p;
            }
            else if (f[head]+(ny-nx)/p==ans1) {
                ans2=min(ans2,nx+(ny-nx)/p*p);
            }
            ++head;
        }
        if (ans1>ans) {
            ans=ans1;
            tail++;
            f[tail]=ans1;
            g[tail]=ans2;
        }
    }
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值