题目链接:小A与任务
题意:
小A手头有 n 份任务,他可以以任意顺序完成这些任务,只有完成当前的任务后,他才能做下一个任务
第 i 个任务需要花费 xi 的时间,同时完成第 i 个任务的时间不能晚于 yi,时间掌控者向小A提出了一个条件:如果完成第 i 个任务的时间本应是 t ,但小A支付 m 个金币的话,他可以帮助小A在 t − m × z 时刻完成第 i 个任务, zi 是时间参数,会在输入中给出
小A想按时完成所有任务,请你帮他制定一个花费金币最少的方案
注意:不能使得某个任务的花费时间小于 0 ,花费的金币可以不是整数:
题解:
贪心
我们首先按照结束时间对这些任务排个序,看看他在截至时间之间做完的话,超出多少时间。
假设在完成第i个任务时,时间超了,那么超出的这段时间我们是需要用金币来完成的,我们设超出的这段时间为t。
那么我们要花费最少的金币,怎么办呢?
因为t是固定的了,根据题目公式
t
=
m
∗
a
[
i
]
.
z
t=m * a[i].z
t=m∗a[i].z
$t /a[i].z=m $
想让m最小,因为t是固定的,那么我们让z尽可能大即可。
那么我们就去找一下已经完成了任务中最大的那个z,他的任务我们用金币来完成,节省下来的时间完成 当前这个工作。
为什么这样呢?因为去完成那个任务的转换比最划算。
就比如说 在相同情况下 A:花1金币可以完成10分钟工作 B:花1金币可以完成1分钟工作。
那么要想让完成时间相同的情况下金币尽量少,我们肯定选择A
怎么快速的找出那个最大的z,那么就用优先队列即可。
再注意一下细节即可。
每次用金币完成的任务时间=超出的这段时间。
已经完成了任务中最大的那个z任务所花费的时间,有可能大于t,也有可能小于t,注意处理即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define endl '\n'
#define int long long
const int maxn=2e5+10;
struct node{
int z,x,y;
}a[maxn];
struct rule{
bool operator()(const node & a,const node & b){
return a.y<b.y;
}
};
struct wazxy{
int x,y,z;
wazxy(int a,int b,int c){x=a,y=b,z=c;}
bool operator<(const wazxy& a)const
{
return z<a.z;
}
};
priority_queue<wazxy> q;
signed main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i].z>>a[i].x>>a[i].y;
}
sort(a,a+n,rule());
int sum=0,pos=0;
double ans=0;
for(int i=0;i<n;i++){
pos+=a[i].x;
q.push(wazxy(a[i].x,a[i].y,a[i].z));
if(pos>a[i].y){
int temp=pos-a[i].y;
pos=a[i].y;
while(true){
wazxy z=q.top();
q.pop();
if(temp>z.x){
ans+=(double)z.x/(double)z.z;
temp-=z.x;
}
else{
ans+=(double)temp/(double)z.z;
q.push(wazxy(z.x-temp,z.y,z.z));
temp=0;
}
if(temp==0) break;
}
}
}
printf("%.1f",ans);
return 0;
}