当前位置: 代码迷 >> 综合 >> 【NOIP2011】洛谷1315 观光公交
  详细解决方案

【NOIP2011】洛谷1315 观光公交

热度:59   发布时间:2024-01-13 11:20:53.0

题目描述

风景迷人的小城Y 市,拥有n 个美丽的景点。由于慕名而来的游客越来越多,Y
市特意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第 0 分钟出现在 1号景点,随后依次前往 2、3 、4 ……n
号景点。从第 i 号景点开到第 i+1 号景点需要 Di 分钟。任意时刻,公交车只能往前开,或在景点处等待。

设共有m 个游客,每位游客需要乘车1 次从一个景点到达另一个景点,第i 位游客在Ti 分钟来到景点 Ai ,希望乘车前往景点Bi (Ai< B

i )。为了使所有乘客都能顺利到达目的地,公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。

假设乘客上下车不需要时间。

一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司机ZZ给公交车安装了
k 个氮气加速器,每使用一个加速器,可以使其中一个 Di 减1 。对于同一个Di 可以重复使用加速器,但是必须保证使用后Di 大于等于0 。

那么ZZ该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?

每次贪心地选取能“惠及”最多人的位置。
记录下在每个位置下车的人数、每个位置到的最晚的人的到达时间和当前情况每个位置的到达时间。然后可以O(n)扫一遍找见能“惠及”最多人的位置,然后再O(n)暴力维护,总复杂度O(nk)。
具体求法是维护sum[i]表示在i..i+1段加速能惠及的人数。首先一定能惠及的是在i+1处下车的人,其次如果到了i+1不用等人的话,还可以加上之后惠及的人数,即sum[i+1]。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,k,d[1010],t[10010],a[10010],b[10010],
num[1010],last[1010],arr[1010],sum[1010];
int main()
{int i,j,p,q,x,y,z,ans,tem;scanf("%d%d%d",&n,&m,&k);for (i=1;i<n;i++)scanf("%d",&d[i]);for (i=1;i<=m;i++)scanf("%d%d%d",&t[i],&a[i],&b[i]);for (i=1;i<=m;i++){num[b[i]]++;last[a[i]]=max(last[a[i]],t[i]);}for (i=2;i<=n;i++)arr[i]=max(arr[i-1],last[i-1])+d[i-1];ans=0;for (i=1;i<=m;i++)ans+=arr[b[i]]-t[i];while (k--){p=tem=-1;for (i=n-1;i;i--){if (arr[i+1]<=last[i+1]) sum[i]=num[i+1];else sum[i]=num[i+1]+sum[i+1];if (sum[i]>tem&&d[i]){tem=sum[i];p=i;}}if (p==-1) break;ans-=tem;d[p]--;for (i=p+1;i<=n;i++)arr[i]=max(arr[i-1],last[i-1])+d[i-1];}printf("%d\n",ans);
}