2007-2008 Winter Petrozavodsk Camp, Andrew Stankevich Contest 30-G - Pulp Fiction-贪心+优先队列

http://codeforces.com/gym/100345/problem/G


题意:两兄弟要合作写n本书

接下来有n对 ri,pi,表示这本书在第ri天被弟弟构思完成,需要花pi天被哥哥写完


哥哥写正在写A书时,可以跳去写B书,然后再回来写A书(也可以再跳去写C书)


每本书写完的时间是Ci。最ci之和最小值


思路: 如果要写n本数,那么前面不管顺序怎么变,第n本最早写完的时间是不变的。

既然如此,要ci和最小,我们就让前面的出书时间尽可能小。 以此类推,我们只需要让书出的尽可能早即可得到最小和。


因此,一开始对 ri排序,然后遍历:

每次把ri节点丢入,【按p从小到大排序】的优先队列,

我们考虑在ri时间的当前队列的书,最早出的一本数一定是pi最小的【优先队列的pi是指离当前Ri时间还需要p时间完书】    因此从ri到ri+1这一段时间里,我们就用来写 pi最小的书,如果时间足够多,写完了一本时间还有剩余,则一直写下去。直到不够写完一本书,则更新这本书的p,即p减去已写的部分。。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
 
const double pi=acos(-1.0);
double eps=0.000001; 
__int64 min(__int64 a,__int64 b)
{return a<b?a:b;} 
__int64 max(__int64 a,__int64 b)
{return a>b?a:b;}

struct node
{
	__int64 r,p;
	node(){}
	node(__int64 a,__int64 b){r=a,p=b;}
	bool operator <(const node &b ) const 
	{
		return p>b.p;
	}
};
node tm[100005]; 
priority_queue<node >q; 
bool cmp(node a,node b)
{return a.r<b.r;}
int main()
{
  	 freopen( "pulp.in","r",stdin ); // scanf 从1.txt输入
	  freopen( "pulp.out","w",stdout );  //printf输出到1.tx
	__int64 n;
	scanf("%I64d",&n);
	__int64 i;
	for(i=1;i<=n;i++)
	{
		scanf("%I64d%I64d",&tm[i].r,&tm[i].p);
	} 
	sort(tm+1,tm+1+n,cmp);
	__int64 sum=0;
	tm[n+1].r=1e18;
	for (i=1;i<=n;i++)
	{
		q.push(tm[i]);
		node tt=q.top();	
		q.pop();
		__int64 has=tm[i+1].r-tm[i].r;
		__int64 last=tm[i].r;
		while (has>=tt.p)
		{ 
			last+=tt.p;			//更新当前时间
			sum+=last;			//累计答案
			has-=tt.p;			//更新还有的时间
			tt.p=0;				//表示本书写完了
			if (q.empty()) break;  //队列空表示没书需要写了
			tt=q.top();q.pop(); 
		}
		
		if (tt.p)
		{
			 tt.p-=has;
		q.push(tt);
		}
	}	 

	 
printf("%I64d\n",sum);








	return 0;
 
}


你可能感兴趣的:(2007-2008 Winter Petrozavodsk Camp, Andrew Stankevich Contest 30-G - Pulp Fiction-贪心+优先队列)