【2015-2016 ACM-ICPC, NEERC, Southern Subregional Contest F】【贪心+ STL-优先队列】 Gourmet and Banquet 最大活动时间

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=105,M=0,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int n,m;
pair<int,int>a[N];
pair<int,int>b[N<<1];
int v[N];
struct node
{
	int o,ed;
	node(){}
	node(int o_,int ed_){o=o_;ed=ed_;}
	bool operator < (const node& b)const 
	{
		return ed>b.ed;
	}
};
priority_queue<node>q;
bool ok(int tim)
{
	for(int i=1;i<=n;i++)v[i]=tim;
	while(!q.empty())q.pop();
	for(int i=1;i<=m;i++)
	{
		int t=b[i].first-b[i-1].first;
		while(t&&!q.empty())
		{
			int o=q.top().o;
			int ed=q.top().ed;
			q.pop();
			int need=min(v[o],t);
			v[o]-=need;
			t-=need;
			if(v[o])q.push(node(o,ed));
		}
		int o=b[i].second;
		if(o<0)q.push(node(-o,a[-o].second));//新的任务加入
		else if(v[o]>0)return 0;//时间到了却还没有做完
	}
	return 1;
}
int main()
{
	while(~scanf("%d",&n))
	{
		m=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d",&a[i].first,&a[i].second);
			b[++m]=MP(a[i].first,-i);
			b[++m]=MP(a[i].second,i);
		}
		sort(b+1,b+m+1);
		int l=0;
		int r=10000/n;
		while(l<r)
		{
			int mid=(l+r+1)>>1;
			if(ok(mid))l=mid;
			else r=mid-1;
		}
		printf("%d\n",l*n);
	}
	return 0;
}
/*
【trick&&吐槽】
比赛的时候因为n很小,我们甚至可以采取O(log(10000)*n*10000)的复杂度做。
然而当然时候可以用更小复杂度的做法啦啦啦~~

【题意】
有n([1,100])种活动,每个活动有一个开始时间st和结束时间ed(0<=st<=ed<=10000)。
我们想要从事每种活动以相同的时间,使得最终参与活动的总时间尽可能多。

【类型】
贪心+
STL-优先队列 or 暴力

【分析】
我们发现,总的从事活动的上界也不过才只有10000,于是答案不过超过10000,且一定是n的倍数。
于是——

1,枚举从事每个活动的时间w(这个可以二分)
2,然后从前面的时间点开始往后贪。
	对于一个时间点,我们从事什么活动呢?
	因为对于每个活动,都要强行参与w的时间。
	于是,如果有多个排在了一起,我们肯定也选择结束时间早的。

具体实现,可以是二分+10000vector的暴力选择,也可以是二分+双关键字排序priority_queue做。
priority_queue:
1,读入原始的pair a[],并且把每个pair拆成入点和出点,放到b[]中。
	入点和出点对应着这个点的编号,和这个活动开始与结束的时刻。

2,把b[]做排序,也就是按照时刻排序,然后对b[]做顺序扫描。
	在每个时间点之前,都有一个空余时间段。
	我们还有任务没有完成(取出结束时间最早的),并且还有空余时间,那么我们就去做这个任务。
	如果没做完,就把它再加回优先队列中。
	然后开始处理这个时间点的事情了。
	first,如果有新的任务出现,我们把它加进优先队列中
	second,如果当前队列首的任务无法完成,就return 0

【时间复杂度&&优化】
O(nlogn)

*/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值