noip2011观光公交

话说这题是一个贪心。。。

我们设s表示i-1到i号点的距离,ar、to、dow如题意所设,now表示汽车到当前点的来的最迟的乘客的来到时间,out表示i号点下车的人数,arr表示车正常走到i点的时间(要拉上每一位乘客);

  • 我们会发现每次贪心找覆盖了最多人的一个点进行加速一定是最优的,所以我们从后往前枚举i,f数组表示在i号点加速可以覆盖多少人,这样的话有两种情况: 第一种就是arr>now,那么就是如果你把这个加速器用在这儿的话一定就会影响到i+1号店可以覆盖的人数和这个点下车的人,他们的旅行时间都会减少1;另一种则是now<=arr,这种情况的话你加速其实不会影响乘客等车的时间,而只会影响这个站点下车的人
  • 所以再统计答案就好
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k;
int s[1010],ar[10100],to[10100],dow[10100];
int now[10100],out[10100],arr[10100],f[10100],vis[10100];
int main(){
	cin>>n>>m>>k;
	for(int i=2;i<=n;i++){
		cin>>s[i];
	}
	for(int i=1;i<=m;i++){
		cin>>ar[i]>>to[i]>>dow[i];
		now[to[i]]=max(now[to[i]],ar[i]);
		out[dow[i]]++;
	}
	//ar[1]=now[1];
	for(int i=2;i<=n;i++){
		arr[i]=max(now[i-1],arr[i-1])+s[i];
	}
	while(k>0){
		memset(vis,0,sizeof(vis));
		for(int j=n;j>=2;j--){
			if(s[j]==0) vis[j]=1;
		    if(arr[j]>now[j]){
				//if(j==2) cout<<"%%%"<<" "<<now[j]<<" "<<arr[j]<<" "<<f[j+1]<<endl;
				f[j]=f[j+1]+out[j];
			}
			else if(arr[j]<=now[j]){
				// 
				f[j]=out[j];
			}
		} 
		int maxx=0,ky=0;
		for(int j=1;j<=n;j++){
			if(f[j]>maxx&&!vis[j]){
				ky=j;
				maxx=f[j];
			}
			//cout<<f[j]<<" "<<j<<" "<<endl;
		}
		if(ky==0) break;
		s[ky]--;
		k--;
		for(int j=ky;j<=n;j++)
		  arr[j]=max(arr[j-1],now[j-1])+s[j];
	}
	long long ans=0;
	for(int i=1;i<=m;i++){
		ans+=arr[dow[i]]-ar[i];
		//cout<<arr[dow[i]]<<" "<<ar[i]<<endl;
	}
	cout<<ans<<endl; 
} 

猜你喜欢

转载自blog.csdn.net/weixin_42759194/article/details/81608824