[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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章