电梯 - dp - 单调队列

题目大意:总之就是有个dp[n]=min⁡i=0n−1max⁡{dp,p[i]}+max⁡j=i+1nt[j]\text{dp}[n]=\min_{i=0}^{n-1} \max \{\text{dp},\text p[i]\}+\max_{j=i+1}^{n}\text t[j]dp[n]=mini=0n1max{dp,p[i]}+maxj=i+1nt[j]的dp,要做到线性求dp[n]\text dp[n]dp[n]。保证ttt是正整数,ppp是单调的,dp[0]=0\text{dp}[0]=0dp[0]=0
题解:首先显然dp值是单调的,前面那个max可以分两部分讨论。其次若t[n]≥t[n−1]t[n]\ge t[n-1]t[n]t[n1]那么n−1n-1n1nnn一定在同一段里,因此n−1n-1n1就没有必要了,可以删掉。这样后面那个max也没有了。就直接单调队列即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define fir first
#define sec second
namespace INPUT_SPACE{
    const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;using namespace std;typedef pair<int,int> pii;
const int N=1000010;const lint INF=LLONG_MAX/100;pii p[N];lint val[N],f[N];int id[N],fp,rp;
inline int ins(int x) { lint v=f[x]+p[x+1].sec;while(rp>=fp&&val[rp]>=v) rp--;return val[++rp]=v,id[rp]=x; }
inline int del(int x) { return fp+=(fp<=rp&&id[fp]==x); } inline lint qry() { return fp<=rp?val[fp]:INF; }
int main()
{
    int n=inn(),m=0,j=0;fp=1,rp=0;rep(i,1,n) p[i].fir=inn(),p[i].sec=2*inn();sort(p+1,p+n+1);
    rep(i,1,n) { while(m&&p[i].sec>=p[m].sec) m--;p[++m]=p[i]; }
    rep(i,1,m) { for(ins(i-1);j<i&&f[j]<=p[i].fir;del(j++));f[i]=min((lint)p[i].fir+p[j].sec,qry()); }
    return !printf("%lld\n",f[m]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值