NOIP2011 观光公交

题目描述

风景迷人的小城 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 该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?

输入输出格式

输入第 1 行是3个整数 n, m, k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。 
第 2 行是 n-1 个整数,每两个整数之间用一个空格隔开,第 i 个数表示从第 i 个景点开往第 i+1 个景点所需要的时间,即 Di。 
第 3 行至 m+2 行每行3 个整数 Ti, Ai, Bi,每两个整数之间用一个空格隔开。第 i+2 行表示第 i 位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。输出共一行,包含一个整数,表示最小的总旅行时间。

对于 100%的数据,1 ≤ n ≤ 1,000,1 ≤ m ≤ 10,000,0 ≤ k ≤ 100,000,0 ≤ Di ≤ 100,0 ≤ Ti≤ 100,000。

题解:

稍微想一想,发现,

不能二分(怎么验证合法与否??),不能dp(没有最优子结构性质)

不能模拟(要有决策啊),数据结构好像也不是很像,而且就算是有,也就是一个辅助维护功能罢了。

所以看起来似乎就剩下了贪心??!?!

但是左思右想,不知道怎么个贪心。。。。

这是一道非常神的贪心题目了。

首先有一个基础的事实:

发现,如果车到达某个点,不论早还是晚,至少要在这个点的所有的人都上去以后才能走,所以至少是这个点最后一个人到达的时间

所以,似乎可以从这里入手。

是不是只要是到了这里,如果到这里的时间,会早于这个点最后一个人到达的时间,

最后这条边就不用加速了呢?

貌似有点道理,因为早到晚到都是要等的么。

但是其实是错的!!

因为,对于一些人会在这一站下车,他们不用等到最后一个人上车啊。

如果有很多人在车上,并且都在这一站下车,那么加速一下可能还是很有必要的

(所以很多题解都是错的)

但是,不要放弃,还可以抢救一下。

这个题就是用一种决策,使得总的时间最小

猜想:是不是每次找一个能减少最多总时间的路,减一下?

那么怎么找在i~i+1的路加速一下,会减少多少总时间呢?

其实就是这次加速,能影响到最远到哪一站下车的人。

这个影响范围种影响的人数,就是这次加速减少的总时间。

以下部分摘自:https://blog.csdn.net/qq_37220238/article/details/80059161

假设在第i站使用加速器:

    ①假设观光车到达i+1站的时间小于以i+1站为起点的乘客到达i+1站最晚的时间,说明该观光车到达i+1站之后要等待这位乘客到达之后才会出发;若在i站使用加速器,观光车到达i+1站的时间会变短,使在i+1站下车的乘客的花费时间变短,但是观光车到达i+1站之后仍然要等待这位最晚到达的乘客上车之后才能出发,所以这个加速器的最大有效范围只到i+1站。

    ②假设观光车到达i+1的时间等于以i+1站为起点的乘客到达i+1站最晚的时间,说明该观光车到达i+1站之后等无需等待,直接出发;若在i站使用加速器,观光车到达i+1站的时间会变短,使在i+1站下车的乘客的花费时间变短,但是观光车到达i+1站之后仍然要等待这位最晚到达的乘客上车之后才能出发,所以这个加速器的最大有效范围只到i+1站。

    ③假设观光车到达i+1的时间大于以i+1站为起点的乘客到达i+1站最晚的时间,说明观光车到达i+1车站之后无需等待,直接出发;若在i站使用加速器,则加速器的效果会延续到之后的若干站,则在第i站使用加速器的最大有效范围等于在第i+1站使用加速器的最大有效范围。

代码中,讨论即可。

虽然不太明白影响范围的含义,但是请先往下看

求出这个影响范围,好像还不能直接确定影响多少人啊。

发现,在i加速,假设影响范围边界在j(i小于j)那么,在i+1~j下车的乘客,都可以获得加速。

显然,i以及之前下车的乘客已经毫无关系了。

至于j+1之后的下车的乘客。。。。。

因为到达j之后,加速已经不能影响到后面了。

说明,这次加速之后,一定到达j的时间,比j最后一个人到达的时间要晚!!!

也就是说,到达j之后,目的地在j+1之后的乘客,只能继续等待。不论再怎么加速,还是没有用!

所以,这一部分也不会节省总时间。

所以,就是i+1~j区间下车乘客的人数了。(期间必须在车上,j以及之前,必须下车)

用一个前缀和+差分可以搞定。

首先,预处理下车的前缀和,预处理每个点最后一个上车的人的时间,

找出不用加速时的:到每个点时间,每条边长度。

然后,while(k)

每次k--,循环找出影响范围(每次可能不同),找出节省的时间,选择最多的,把长度-1,最后更新到达每个点的时间。

如果不能节省时间了,就break结束好了。

复杂度理论O(nk)实际情况很快(数据水么)

返回来,刚才那个猜想:“是不是每次找一个能减少最多总时间的路,减一下?”

 为什么是对的?

我们先看一下代码:

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/9578551.html