题意
一个容量为 c c c升的浇水机器,一开始有 c 0 c0 c0升水,它每分钟会消耗 1 1 1升水
有 n n n个人,第 i i i个人会在第 t i t_i ti分钟至多带 a i a_i ai升水过来并把他带的水一次性倒进机器,每升水卖 b i b_i bi元
问要使得抽水机撑到第 m m m分钟不断水(即剩余水量恒 ≥ 0 \ge0 ≥0),最少的花费是多少;如果撑不到,输出 − 1 -1 −1
0 ≤ n ≤ 5 × 1 0 5 , 2 ≤ m ≤ 1 0 9 , 1 ≤ c 0 ≤ c ≤ 1 0 9 0\le n\le5\times10^5,2\le m\le10^9,1\le c0\le c\le10^9 0≤n≤5×105,2≤m≤109,1≤c0≤c≤109
题解
考虑贪心
先把所有人按照按照时间排序
对于第 i i i个人, Δ t i = t i − t i − 1 \Delta t_i=t_i-t_{i-1} Δti=ti−ti−1,我们可以把机器里剩余的水按价格从低到高地用掉,并记录答案
对于每一个人我们把他带的水全部倒进去,直到满了为止,但是先不计费
如果机器里最贵的水价格 > b i \gt b_i >bi,那么我们就可以把最贵的水倒出去一些,再把第 i i i个人的水再倒进去一些(如果还有的话),就相当于那个人来的时候少带了一些水,而且这样也不会影响机器撑到 t i t_i ti
可以发现这样的花费一定是最小的
具体实现可以设 m a p < i n t , i n t > q map<int,int>q map<int,int>q,其中 q [ a ] q[a] q[a]表示机器中剩余的价格为 a a a的水有多少升
用水的时候每次取出最便宜的水(即 q . b e g i n ( ) . s e c o n d q.begin().second q.begin().second)来更新答案,用完后就删除
加水的时候取出最贵的水(即 q . r b e g i n ( ) . f i r s t q.rbegin().first q.rbegin().first)和当前的 b i b_i bi比较,并计算要替换掉多少,完全替换了就删除
时间复杂度 O ( n log n ) O(n\log n) O(nlogn)
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
const int N=5e5+5,M=N<<1;
typedef int arr[N];
typedef long long ll;
struct Water{
int t,a,b;
inline void in(){sd(t),sd(a),sd(b);}
bool operator<(const Water&y)const{return t==y.t?(a==y.a?b<y.b:a<y.a):t<y.t;}
}a[N];
int n,m,c,res;map<int,int>q;
inline ll sol(){
ll ans=0;
sd(n),sd(m),sd(c),sd(res);
fp(i,1,n)a[i].in();
a[++n]=(Water){m,0,0};
sort(a+1,a+n+1);
q.clear();q[0]=res;
fp(i,1,n){
int DeltaT=a[i].t-a[i-1].t;
if(DeltaT>c)return -1;
while(!q.empty()&&DeltaT>0){
int W=min(DeltaT,q.begin()->second);
ans+=(ll)q.begin()->first*W;
q.begin()->second-=W;DeltaT-=W;res-=W;
if(!q.begin()->second)q.erase(q.begin());
}
if(DeltaT)return -1;
int Cnt=a[i].a,Cost=a[i].b,add=min(c-res,Cnt);
res+=add;
while(!q.empty()&&add<Cnt&&Cost<q.rbegin()->first)
if(Cnt-add>=q.rbegin()->second){
add+=q.rbegin()->second;
q.erase(--q.end());
}else{
q.rbegin()->second-=Cnt-add;
add=Cnt;
}
q[Cost]+=add;
}
return ans;
}
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
int q;sd(q);
while(q--)printf("%lld\n",sol());
return 0;
}