YBTOJ 家庭作业(堆的应用)

一个很水的大根堆+贪心。
考虑将所有作业先按照截至日期升序排序,依次加入tot中,同时插入堆中,堆是在a意义下的大根堆。
若tot大于当前作业的截止日期,则取出之前以加入的作业中a最大的作业,进行加速,直到tot=当前作业的截止日期。
正确性很显然:如果不让截止日期小的作业尽量早地完成,则消耗很可能更大。

Code

tips1:我用的是手写堆,因为不太喜欢用重载运算符。
有人喜欢阴间的pair嵌套,但我不说是谁

tips2:一个有意思的bug:

当你想输出一个数据,结果输出的结果是"nan"时,很可能是因为在某一步一个数0除。
"nan"的含义是“not a number”,并不是出数据的人提醒你这道题很难。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n,len;
double tot=0,sum=0;
struct mint
{
	double a,d,b; 
}sav[maxn],heap[maxn];
bool cmp(mint x,mint y)
{
	return x.d < y.d;
}
void insert(mint k)
{
	heap[++len]=k;
//	printf("%lf %lf %lf\n",k.a,k.b,k.d);
	int pla=len;
	while(pla>1)
	{
		int fa=(pla>>1);
		if(heap[fa].a>heap[pla].a) return;
		swap(heap[fa],heap[pla]);
		pla=fa;
	}
}//a是价值,b是所需时间,d是截止日期 
mint get()
{
	mint ans=heap[1];
	heap[1]=heap[len--];
	int pla=1;
	while(pla*2<=len)
	{
		int son=pla<<1;
		if(son+1<=len&&heap[son+1].a>heap[son].a) son++;
		if(heap[son].a<heap[pla].a) break;
		swap(heap[son],heap[pla]);
		pla=son;
	}
	return ans;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%lf%lf%lf",&sav[i].a,&sav[i].b,&sav[i].d);
	sort(sav+1,sav+n+1,cmp);
	for(int i=1;i<=n;++i)
	{
		mint k=sav[i];
		tot+=k.b;
		insert(k);
		if(tot<k.d) continue;
		double deta=tot-k.d; 
		while(deta>0)
		{
			mint g=get();
			if(g.b>=deta)
			{
			//	printf("g.a=%lf",g.a);
				sum+=deta/g.a;
				g.b-=deta;
				if(g.b!=0) insert(g);
				deta=0;
				tot=k.d;
			}
			else
			{
			//	printf("g.a=%lf",g.a);
				sum+=g.b/g.a;
				tot-=g.b;
				deta-=g.b;	
			}
		}
	}
	printf("%.2lf",sum);	
	return 0;
}	
posted @ 2021-09-13 13:56  Mint-hexagram  阅读(96)  评论(0编辑  收藏  举报