[Codeforces 635E] Package Delivery //贪心+栈

题目连接

题意:终点d(<=1e9),中间有m(<=2e5)个加油站,每个加油站一个xi,pi分别表示坐标和单位油价,邮箱容量为n(<=1e9),起初位于位置0,油箱是满的。问到达d点的最小花费,若不能到达输出-1。

思路:①若当前位置 i 加满油能到达后面第一个油价pj<=pi 的加油站,就加到刚好能到达加油站 j 的油量,然后到位置 j。
②否则,即后面能到达的加油站都比当前位置 i 油价高,那就在当前加油站 i 加满油,然后到 i+1的位置。
因为m是2e5,m2找会超时,所以要O(m)或O(mlogm)预处理每个加油站能到达的后面第一个价格<=pi的加油站。这个过程可以用栈维护

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+1000;
typedef long long ll;
ll v,d,ans;
int n,nxt[N];
struct node{
	ll x,p,id;
	bool operator<(const node &o)const{
		return x<o.x;
	}
}a[N];
stack<node>s;
int main(){
	cin>>d>>v>>n;
	for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].x,&a[i].p);
	a[0].p=1e6+1;
	a[n+1].x=d;
	sort(a,a+n+2);
	for(int i=0;i<=n;i++)if(a[i+1].x-a[i].x>v){cout<<-1;return 0;}
	s.push(node{d,0,n+1});
	for(int i=n;i>=1;i--){
		node t=node{0,0,0};
		while(t=s.top(),t.x-a[i].x>v||t.p>a[i].p){
			s.pop(); //i肯定比后面价格>pi的加油站优
			if(s.empty()){t.id=0;break;}//后面不存在价格<=pi的加油站
		}
		nxt[i]=t.id;
		s.push(node{a[i].x,a[i].p,i});
	}
	int i=0;
	ll now=v;
	while(i<=n){
		if(nxt[i]){ //情况1
			ll dis=a[nxt[i]].x-a[i].x;
			if(dis<now)now-=dis;
			else{ans+=a[i].p*(dis-now);now=0;}
			i=nxt[i];
		}else{	//情况2
			ans+=a[i].p*(v-now);
			now=v-(a[i+1].x-a[i].x);
			i++;
		}
	}
	cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/qq_45530271/article/details/105160599