【NOIP2011 day2】观光公交

3.观光公交

(bus.cpp/c/pas)
【问题描述】
风景迷人的小城 Y 市,拥有 n 个美丽的景点。由于慕名而来的游客越来越多,Y 市特
意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第 0 分钟出现在 1
号景点,随后依次前往 2、3、4……n 号景点。从第 i 号景点开到第 i+1 号景点需要 Di 分钟。
任意时刻,公交车只能往前开,或在景点处等待。
设共有 m 个游客,每位游客需要乘车 1 次从一个景点到达另一个景点,第 i 位游客在
Ti 分钟来到景点 Ai,希望乘车前往景点 Bi(Ai < Bi)。为了使所有乘客都能顺利到达目的地,
全国信息学奥林匹克联赛(NOIP2011)复赛 提高组 day2
第 4 页 共 4 页
公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。
假设乘客上下车不需要时间。
一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一
辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司
机 ZZ 给公交车安装了 k 个氮气加速器,每使用一个加速器,可以使其中一个 Di 减 1。对于
同一个 Di 可以重复使用加速器,但是必须保证使用后 Di 大于等于 0。
那么 ZZ 该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?
【输入】
输入文件名为 bus.in。
第 1 行是 3 个整数 n, m, k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数
和氮气加速器个数。
第 2 行是 n-1 个整数,每两个整数之间用一个空格隔开,第 i 个数表示从第 i 个景点开
往第 i+1 个景点所需要的时间,即 Di。
第 3 行至 m+2 行每行 3 个整数 Ti, Ai, Bi,每两个整数之间用一个空格隔开。第 i+2 行表
示第 i 位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。
【输出】
输出文件名为 bus.out。共一行,包含一个整数,表示最小的总旅行时间。
【输入输出样例】
bus.in bus.out
3 3 2
1 4
0 1 3
1 1 2
5 2 3
10
【输入输出样例说明】
对 D2 使用 2 个加速器,从 2 号景点到 3 号景点时间变为 2 分钟。
公交车在第 1 分钟从 1 号景点出发,第 2 分钟到达 2 号景点,第 5 分钟从 2 号景点出发,
第 7 分钟到达 3 号景点。
第 1 个旅客旅行时间 7-0 = 7 分钟。
第 2 个旅客旅行时间 2-1 = 1 分钟。
第 3 个旅客旅行时间 7-5 = 2 分钟。
总时间 7+1+2 = 10 分钟。
【数据范围】
对于 10%的数据,k=0;
对于 20%的数据,k=1;
对于 40%的数据,2 ≤ n ≤ 50,1 ≤ m ≤ 1,000,0 ≤ k ≤ 20,0 ≤ Di ≤ 10,0 ≤ Ti ≤ 500;
对于 60%的数据,1 ≤ n ≤ 100,1 ≤ m ≤ 1,000,0 ≤ k ≤ 100,0 ≤ Di ≤ 100,0 ≤ Ti ≤ 10,000;
对于 100%的数据,1 ≤ n ≤ 1,000,1 ≤ m ≤ 10,000,0 ≤ k ≤ 100,000,0 ≤ Di ≤ 100,
0 ≤ Ti ≤ 100,000。

首先考虑到就是把氮气加速器放在人多的时候用,那么在某一段路上使用氮气加速器的影响是什么呢?
如果公交车在第i个车站需要停留 (arr[i]<sta[i]) ,那么现在在车上的人必定受到影响。
所以对于每一个氮气加速器的使用,我们可以从后往前遍历每一个公交车站,统计后缀(即影响的人数),如果要停留,则设其为断点,重新累加,找到最有价值的一段公路后,使用氮气加速器,并重新计算到达和离开时间。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

#define MAXN 1000
#define MAXM 10000
#define INF 0x3f3f3f3f
typedef long long int LL;

int dist[MAXN+10];
int arr[MAXN+10],sta[MAXN+10];
int out[MAXN+10],man[MAXN+10];
int N,M,K;
int ans=0;

int main()
{
    //freopen("bus.in","r",stdin);
    //freopen("bus.out","w",stdout);

    scanf("%d%d%d",&N,&M,&K);
    int i,j;

    for(i=1;i<N;++i)
        scanf("%d",&dist[i]);

    int a,b,c;
    for(i=1;i<=M;++i)
    {
        scanf("%d%d%d",&c,&a,&b);
        ++out[b];
        sta[a]=max(sta[a],c);
        ans-=c;//管你什么时候出来的,全都给我回去
    }

    while(K--)
    {
        memset(man,0,sizeof(man));

        for(i=2;i<=N;++i)//让我看看我到这里现在要多久
            arr[i]=max(arr[i-1],sta[i-1])+dist[i-1];

        for(i=N;i>1;--i)
        {
            if(dist[i-1])
            {
                man[i-1]=out[i];
                if(arr[i]>sta[i])
                    man[i-1]+=man[i];//哎呀,不用等,直接飞吧
            }
            else man[i-1]=0;//这条路不能被删了,再删就废了
        }

        int MaxVal=0,times,pos=-1;
        for(i=1;i<N;++i)
            if(MaxVal<man[i])
            {
                MaxVal=man[i];
                times=
                pos=i;
            }

        if(pos==-1)break;//删不下去了,不删了
        else --dist[pos];
    }

    for(i=2;i<=N;++i)//让我看看我到这里现在要多久
        arr[i]=max(arr[i-1],sta[i-1])+dist[i-1];

    for(i=1;i<=N;++i)
        ans+=arr[i]*out[i];

    printf("%d\n",ans);

    //fclose(stdin);
    //fclose(stdout);
}

/*
3 3 8
1 4
0 1 3
1 1 2
5 2 3

2 5 110
100
1 1 2
100 1 2
9 1 2
65 1 2
4 1 2

10 5 0
5 7 2 4 8 2 8 3 1
10 3 4
1 1 3
33 6 9
14 4 8
1 1 4

*/
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值