[FROM LUOGU]观光公交

传送门

SOL
挺不错的一道贪心题,小学奥数的较多
最开始分析样例,很多人可能会考虑直接让所有氮气加速器用在下车人数最多的那个车站的前面那条路上,不过发现有车等人、人等车的问题之后,你可能就会觉得这道题不是一个贪心题了
事实上,这还是一道贪心题,只不过kk次氮气加速要一次一次的使用,这个思路应该能够在尝试推导k=1k=1的做法之后想到,用一次氮气加速时,我们考虑人等车的区间贡献最大的一段,并且保证用了之后不会变成车等人,也就是目前车到达站点的时间beg[i]beg[i]大于最晚到此站的人的时间last[i]last[i],求出这么一段区间,然后对最前面那一段使用一次氮气加速,那么整个区间的时间都会减少,求出下车人数最多的一段即可
用了一次之后,可能会出现有些地方从人等车变成车等人,因此要从头考虑,做完kk次统计答案即可
复杂度O(kn)O(k*n)

代码:

#include<bits/stdc++.h>
#define re register
using namespace std;
inline int rd(){
	int data=0;static char ch=0;ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))data=(data<<1)+(data<<3)+(ch^48),ch=getchar();
	return data;
}
const int M=1e4+5,N=1005;
int n,m,k,st[M],ed[M],ans,dis[N],off[N],last[N],beg[N],tim,mx,now,pos;
signed main(){
	n=rd(),m=rd(),k=rd();
	for(int re i=1;i^n;++i)dis[i]=rd();
	for(int re v,i=1;i<=m;++i)st[i]=rd(),v=rd(),ed[i]=rd(),last[v]=max(last[v],st[i]),++off[ed[i]];
	for(int re i=1;i<=n;++i)beg[i]=tim,tim=max(tim,last[i]),tim+=dis[i];
	while(k--){
		mx=0;
		for(int re i=2;i<=n;++i){
			if(!dis[i-1])continue;
			now=0;
			for(int re j=i;j<=n;++j){
				now+=off[j];
				if(beg[j]<=last[j])break;
			}if(now>mx)mx=now,pos=i;
		}--dis[pos-1];
		for(int re i=pos;i<=n;++i){
			--beg[i];
			if(beg[i]<last[i])break;
		}
	}
	for(int re i=1;i<=m;++i)ans+=beg[ed[i]]-st[i];
	printf("%d",ans),exit(0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章