题意:有 1∼n1 \sim n1∼n nnn 个城市排成一行,给定每个城市的单位距离油价和两个城市间的距离、油箱容量,求 111 到 nnn 最小代价。
用 multiset 来维护当前油箱中的油的价格。
在每个城市假装把油加满。如果发现这个城市的油比油箱里的一些便宜,就把这些油都退掉。
跑的时候用油箱里最便宜的油。到达终点后如果有多余的油就全部退掉。
合法性:退掉的油是从买的时候到现在为止没有用过的,退掉相当于没有买。
最优性:因为每次油都加满了,如果不优会被退掉,感性理解是最优的。
复杂度 O(nlogn)O(n\log n)O(nlogn)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <set>
#include <utility>
#define MAXN 100005
using namespace std;
typedef long long ll;
inline int read()
{int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
int d[MAXN],c[MAXN];
typedef pair<int,int> pi;
multiset<pi> s;
int main()
{freopen("drive.in","r",stdin);freopen("drive.out","w",stdout);int n,m;n=read(),m=read();for (int i=1;i<=n;i++) d[i]=read();d[n+2]=d[n+1]=d[n];for (int i=1;i<=n;i++) c[i]=read();int res=m;ll ans=0;for (int i=1;i<=n+1;i++){while (!s.empty()&&s.rbegin()->first>=c[i]) res+=s.rbegin()->second,ans-=(ll)s.rbegin()->first*s.rbegin()->second,s.erase(--s.end());s.insert(make_pair(c[i],res)),ans+=(ll)c[i]*res,res=0;int t=res=d[i+1]-d[i];if (t>m) return puts("-1"),0;while (!s.empty()&&t>=s.begin()->second) t-=s.begin()->second,s.erase(s.begin());if (!s.empty()){pi tmp=*s.begin();s.erase(s.begin());tmp.second-=t;s.insert(tmp);}}cout<<ans;return 0;
}