• 观光公交(codevs 1139)


    题目描述 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 Description

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

    输出描述 Output Description

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

    样例输入 Sample Input

    3 3 2
    1 4
    0 1 3
    1 1 2
    5 2 3

    样例输出 Sample Output

    10

    数据范围及提示 Data Size & Hint

    对 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。

    /*
      刚开始做只得了10分,应该是贪心思路有问题
       
      tim[i]表示到达i站的时刻 
      last[i]表示i站的出发最晚时刻
      sum[i]表示在i站之前或在i站下车的人数
      f[i]表示在i站放一个加速器可能会影响的点的数量
      (在i站放一个加速器会对一部分后面的点产生影响) 
    */
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #define N 10010
    using namespace std ;
    int f[N],sum[N],dis[N],b[N],last[N],tim[N];
    int n,m,k,total,ans;
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i< n;i++)
          scanf("%d",&dis[i]);
        for(int i=1;i<=m;i++) 
        {
            int a,c;
            scanf("%d%d%d",&c,&a,&b[i]);
            total+=c;
            last[a]=max(last[a],c);
            for(int j=b[i];j<=n;j++) 
              sum[j]++;
        }
        while(k--)
        {
            for(int i=2;i<=n;i++)
              tim[i]=max(tim[i-1],last[i-1])+dis[i-1];
            f[n]=0;
            for(int i=n-1;i;i--)
             if(tim[i+1]>last[i+1])//last作为一个限定条件 
               f[i]=f[i+1]+1;
             else f[i]=1;
            
            int maxn=-1,maxpos=0;
            for(int i=1;i<n;i++)
              if(dis[i]&&f[i]&&sum[f[i]+i]-sum[i]>maxn)
              {
                maxn=sum[f[i]+i]-sum[i];
                maxpos=i;
              }
            if(maxpos)dis[maxpos]--; 
        }
        for(int i=2;i<=n;i++)
          tim[i]=max(tim[i-1],last[i-1])+dis[i-1];
        for(int i=1;i<=m;i++)
          ans+=tim[b[i]];
        printf("%d",ans-total);
    }
    View Code
  • 相关阅读:
    代码品质
    窖藏好题
    最后一次模拟
    几个有意思的题目
    【数组练习】
    【复习】图论
    【复习】后缀数组
    The Usage Of Difference Table
    【复习】NTT注意事项
    CF999E Reachability from the Capital
  • 原文地址:https://www.cnblogs.com/harden/p/5650933.html
Copyright © 2020-2023  润新知