Luogu 1315 【NOIP2011】观光公交 (贪心)

Description

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

任意时刻,公交车只能往前开,或在景点处等待。

设共有m 个游客,每位游客需要乘车1 次从一个景点到达另一个景点,第i 位游客在Ti 分钟来到景点Ai,希望乘车前往景点Bi(Ai<bi)。为了使所有乘客都能顺利到达目的地,公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。

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

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

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

Input

第1 行是3 个整数n, m,k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。

第2 行是n-1 个整数,每两个整数之间用一个空格隔开,第i个数表示从第i个景点开往第i+1 个景点所需要的时间,即Di。

第3 行至m+2 行每行3 个整数Ti, Ai,Bi,每两个整数之间用一个空格隔开。第i+2 行表示第i 位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。

Output

共一行,包含一个整数,表示最小的总旅行时间。

Sample Input

3 3 2

1 4

0 1 3

1 1 2

5 2 3

Sample Output

10

Http

Luogu:https://www.luogu.org/problem/show?pid=1315

Source

贪心

解决思路

首先可以贪心的想到,要让每一个加速器的效应最大,那么要让其作用的人最多,所以我们可以想到是一个取最大值的操作。

再来考虑每一个景点。首先如果当前公交车到达某一个景点后还要等乘客,这时在前面这条路上使用加速器是不实用的,因为同样还要等,没有必要浪费。即我们可以得出一个结论,就是公交车从一个景点出发的理论最晚时间(LastTime)就是这个景点的最后来的那个人的时间。

所以,我们可以先把不使用加速器的总时间算出来,然后再最优地减去最多的时间。

不使用加速器的总时间是多少呢?

\[Ans=\sum_{i-1}^{m}LeaveTime[Ranger[i]]-PeopleTime[i]
\]

\(Ranger[i]\)代表第i个人的终点景点

\(PeopleTime[i]\)代表第i个人到来的时间

\(LeaveTime[i]\)表示从i点出发的实际时间,那么\(LeaveTime[i]=max(LeaveTime[i-1],LastTime[i-1])+Dist[i-1]\)

其中\(Dist[i-1]\)表示第i-1个景点到景点i消耗的时间。

从计算总时间的式子可以看出,\(PeopleTime[i]\)是不会变的,我们能减少的就是\(LeaveTime[]\)这一部分。

也就是说,我们要使得每一个人尽可能地早下车

然后考虑如何取这个最优

首先需要知道的是,如果我们对一条路上的时间-1,那么它影响的不仅仅只是这条路,还可能会影响到后面的若干条路。如果\(LeaveTime[i]>LastTime[i]\),也就是说在第i个点上,最晚来的那个人也要等一下,那么如果公交车来早1,这个景点的所有人就都可以早出发1,这也就导致后面的时间都会提早1,向后传递。否则,若在第i个景点,公交车本来就要等最后一个人来,那么此时公交车来早1,同样还是要等到那个时间,后面的时间不会因此改变,所以不会影响后面。

具体在实现上面的计算时,我们用LastInfluence[i]代表第i+1个景点最远能影响到的景点。为什么这里是第i+1呢?因为实际上我们在计算影响时是根据两点之间的边来算的,但后面统计又要用到人,所以把边换成对点的操作。

那么对于从i到\(LastInfluence[i]\)这其中我们要统计什么呢?

结合我们上面所说的让每个人尽早下车,我们统计一下每一个景点下车的人数,那么如果我们把第i条边的时间-1,那么对于景点i到景点\(LastInfluence[i]\)这其中所有下车的人的时间都-1。那么现在的问题就是要找出这些影响区间所覆盖的下车人数最大。简单来说,就是区间最大和。这个最大和,我们可以用前缀和来维护。

注意,每使用一次加速器,要把LeaveTime[i]重新统计,因为使用加速器后会有一条边的时间减少,对应的会影响一段区间的时间,所以要重新计算。

简单地总结一下,此题的步骤就是

1.求出不使用加速器时的总时间

2.每一次找出一个影响区间覆盖的下车人数最多的区间,减去对应的答案,并重新统计实际出发时间,以此进行下次求值。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std; const int maxN=2000;
const int maxM=20000;
const int inf=2147483647; int n,m,K;
int Dist[maxN];
int EndSum[maxN];//EndSum[i]表示在i号位置下车的人的数量,输入完后,再用来计算前缀和
int Rangel[maxM];//人出发的景点
int Ranger[maxM];//人到达的景点
int PeopleTime[maxM];//人到达景点的时间
int LastTime[maxN];//最后到达的人的时间
int LeaveTime[maxN];//离开的时间
int LastInfluence[maxN];//影响区间 void init();//计算LeaveTime数组 int main()
{
memset(LastTime,0,sizeof(LastTime));
memset(EndSum,0,sizeof(EndSum));
scanf("%d%d%d",&n,&m,&K);
for (int i=1;i<n;i++)
scanf("%d",&Dist[i]);
Dist[n]=0;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&PeopleTime[i],&Rangel[i],&Ranger[i]);
EndSum[Ranger[i]]++;
LastTime[Rangel[i]]=max(LastTime[Rangel[i]],PeopleTime[i]);
}
int Ans=0;
for (int i=1;i<=n;i++)//计算前缀和
EndSum[i]+=EndSum[i-1];
init();
for (int i=1;i<=m;i++)//统计不使用加速器时的总时间
Ans+=LeaveTime[Ranger[i]]-PeopleTime[i];
while (K--)
{
LastInfluence[n]=LastInfluence[n-1]=n;//倒着推出每一个景点向后最远能影响到哪里
for (int i=n-2;i>=1;i--)
LastInfluence[i]=(LeaveTime[i+1]<=LastTime[i+1])?i+1:LastInfluence[i+1];//感谢@泪眼问花花不语 找到一个错误
int nowmax=0,id;//求出最大区间和
for (int i=1;i<n;i++)
if ((EndSum[LastInfluence[i]]-EndSum[i]>nowmax)&&(Dist[i]!=0))
{
nowmax=EndSum[LastInfluence[i]]-EndSum[i];
id=i;
}
Dist[id]--;//减去使用加速器造成的效果
Ans-=nowmax;
init();//重新计算LeaveTime
}
printf("%d\n",Ans);
return 0;
} void init()
{
LeaveTime[1]=LastTime[1];
for (int i=2;i<=n;i++)
LeaveTime[i]=max(LastTime[i-1],LeaveTime[i-1])+Dist[i-1];
return;
}

最新文章

  1. SCNU 2015ACM新生赛决赛【F. Oyk闯机关】解题报告
  2. Net设计模式实例之原型模式( Prototype Pattern)
  3. Nginx中文详解、配置部署及高并发优化
  4. 用于svn添加当前目录下所有未追踪的文件,和删除所有手动删除的文件的脚本
  5. java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory 解决方案
  6. 不支持关键字“metadata”问题的解决方法
  7. jquery ready 延迟
  8. DB Query Analyzer 5.05 is released, 65 articles concerned have been published
  9. TestNG实现用例运行失败自动截图(转载)
  10. lodash 判断一个数据是否包含另一个数组
  11. [转载]持续交付和DevOps的前世今生
  12. Kafka学习入门
  13. jQuery 发送验证码倒计时按钮
  14. C语言位操作初步
  15. JSON的多样格式
  16. windowsError:32
  17. YUV转换成RGB算法
  18. Android基础之使用Fragment控制切换多个页面
  19. Linux LVM管理
  20. 就来推荐一本2018年研究的Web书《移动Web前端高效开发实战》

热门文章

  1. (8)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- Ocelot网关(Api GateWay)
  2. LeetCode Pow(x, n) (快速幂)
  3. BugkuCTF 计算器
  4. 如何解决jersey框架中以json格式返回数组,当数组中元素一个时json格式不对
  5. 20135218 Linux 实践二 编译模块
  6. 第二个spring,第三天
  7. PAT 1007 素数对猜想
  8. A KeyValuePair in Java
  9. fasterxml.jackson 将对象转换为json报错处理
  10. python排序