题目概述
有 n+1 个城市, 0 是起点
解题报告
以前做过的贪心题……贪心想法不难,主要是要考虑完整。
从 0 开始,在能走到的点中选出油价比
- 有,那么加能恰好走到该点的油,走到该点。
- 没有,那么在 0 加满油,走到油价最小的点。
如此重复即可。
以前做的时候
示例程序
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100000,Log=16,MAXINT=((1<<30)-1)*2+1;
int n,now,MAX,cst[maxn+5];LL dis[maxn+5],ans;
int top,stk[maxn+5],nxt[maxn+5],RMQ[maxn+5][Log+5];
#define Eoln(x) ((x)==10||(x)==13||(x)==EOF)
inline char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF;return *l++;
}
inline int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst='+';
while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=(tot<<1)+(tot<<3)+ch-48,ch=readc();
return x=tot*f,Eoln(ch);
}
#define Miner(x,y) (cst[x]<cst[y]?x:y)
void Make()
{
for (int j=1,k=log2(n);j<=k;j++)
for (int i=1;i<=n-(1<<j)+1;i++)
RMQ[i][j]=Miner(RMQ[i][j-1],RMQ[i+(1<<j-1)][j-1]);
for (int i=n;i>=1;i--)
{
while (top&&cst[i]<=cst[stk[top]]) top--;
nxt[i]=stk[top];stk[++top]=i;
}
}
inline int Min(int L,int R) {int j=log2(R-L+1);return Miner(RMQ[L][j],RMQ[R-(1<<j)+1][j]);}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);readi(MAX);
for (int i=1,x;i<=n;i++)
{
readi(x);readi(cst[RMQ[i][0]=i]);
dis[i+1]=dis[i]+x;
}
n++;cst[RMQ[n][0]=n]=MAXINT;Make();
for (int i=1,R=1,j;i<n;now-=dis[j]-dis[i],i=j)
{
while (R<=n&&dis[R]<=dis[i]+MAX) R++;
if (i==R-1) return printf("-1\n"),0;
if (nxt[i]&&nxt[i]<R)
{
j=nxt[i];LL tem=max(dis[j]-dis[i]-now,(LL)0);
ans+=tem*cst[i];now+=tem;
} else
{
if (dis[i]+MAX>=dis[n]) {ans+=max(dis[n]-dis[i]-now,(LL)0)*cst[i];break;}
j=Min(i+1,R-1);ans+=(LL)(MAX-now)*cst[i];now=MAX;
}
}
return printf("%lld\n",ans),0;
}