大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。江山如画,一时多少豪杰。遥想公瑾当年,小乔初嫁了,雄姿英发。羽扇纶巾,谈笑间,樯橹灰飞烟灭。故国神游,多情应笑我,早生华发。人生如梦,一尊还酹江月。

Noip2011 Day2T3 观光公交

贪心

自己写了一份丑陋的代码,又参考yxc老师的代码重写了一份

证明(参考yxc老师):

三条性质(详细的证明见笔记):

  1. 如果加速某一点,可以加速某一段,故加速起点最优。
  2. 不同的段互相独立
  3. 若加速区间的起点,可能导致区间分裂,且区间权值不会更优

由这三条可以证明先取大的一定最优

一些坑点:

  1. 区间[ l , r ]的权值=[l+1,r]的下车人数。
  2. 第一条性质是没有用的(yxc老师对不起了),我们不一定只加速区间的起点,因为若起点不能再加速,也可以加速区间的其他位置,所以每个点的贡献都要统计,而不是只统计区间的左端点。
  3. 具体实现时,每到达一个站,就要把区间的左端点到当前站的上一个位置的贡献都加上该站下车的人数。复杂度\(O(N*N*K)\),但是数据水能过。yxc老师选择倒序枚举,从右边跑到左边,可以用前缀和优化。复杂度\(O(n*k)\)
  4. 我的代码就是纯模拟,参数大,复杂度大,而 yxc 老师用了递推,预处理出到达 i 站点的时间,从 i 出发的人的最晚时间等,大大简化了代码复杂度。

两份代码:

#include<bits/stdc++.h>
using namespace std;

#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)

const int N=1e3+10,M=1e4+10;

int n,m,K,d[N],tim[N],t[M],a[M],b[M],dn[N],reduce[N],last[N];

int main(){
	cin>>n>>m>>K;
	go(i,1,n-1) scanf("%d",&d[i]);
	go(i,1,m){
		scanf("%d%d%d",&t[i],&a[i],&b[i]);
		++dn[b[i]];last[a[i]]=max(last[a[i]],t[i]);
	}
	go(i,1,n) tim[i]=max(tim[i-1],last[i-1])+d[i-1];
	while(K--){
		com(i,n,2){
			reduce[i-1]=dn[i];
			if(tim[i]>last[i]) reduce[i-1]+=reduce[i];
		}
		int id=0;
		go(i,1,n-1) if(d[i]&&reduce[id]<reduce[i]) id=i;
		if(!id) break;
		--d[id];
		go(i,id+1,n) tim[i]=max(tim[i-1],last[i-1])+d[i-1];
	}
	int ans=0;
	go(i,1,m) ans+=tim[b[i]]-t[i];
	cout<<ans;
}
#include<bits/stdc++.h>
using namespace std;

#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define fo(i,a) for(int i=0;i<a;++i)

const int inf=0x3f3f3f3f,N=1010,M=10010;

int n,m,k,d[N],t[M],last[N],st[M],dn[N],pas[N];
vector<int>up[N];

inline void read(int &x){
	x=0;char c=getchar(),f=1;
	while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
	while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
	x*=f;
}

void work(int &arr,int &bg,int &mx,int &id){
	mem(pas,0);
	go(i,2,n){
		go(j,bg,i-1) pas[j]+=dn[i];
		arr+=d[i-1];
		if(arr<=last[i]){
			bg=i;
			arr=last[i];
		}
	}
	go(i,1,n-1) if(pas[i]>mx&&d[i]) mx=pas[i],id=i;
}


int main(){
	read(n),read(m),read(k);
	go(i,1,n-1) read(d[i]);
	int x;
	go(i,1,m){
		read(t[i]);
		read(x);up[x].push_back(i),last[x]=max(last[x],t[i]);
		read(x);++dn[x];
	}
	while(k--){
		int arr=last[1];
		int id=0,mx=0,bg=1;
		work(arr,bg,mx,id);
		if(!id) break;
		--d[id];
	}
	int ans=0,now=0,arr=0,tmp;
	go(i,1,n){
		tmp=arr;
		arr+=d[i-1];
		arr=max(arr,last[i]);
		ans+=dn[i]*d[i-1];
		now-=dn[i];
		ans+=now*(arr-tmp);
		fo(j,up[i].size()){
			x=up[i][j];
			ans+=arr-t[x];
		}
		now+=up[i].size();
	}
	cout<<ans;
	return 0;
}
posted @ 2019-10-18 11:45  White_star  阅读(132)  评论(0编辑  收藏  举报
}