P1315 观光公交

P1315 观光公交

题解

贪心大法好啊

 

思路:
先计算出不加速的时候的时间
然后考虑在哪里加速
用一开始的时间不断减就好啦

 

先考虑不加速:
由于人到达车站的时间是不会改变的
所以每个车站的出发时间是不会改变的
就是:start[ i ] = max(last[ i ] , arrive[ i ])
          arrive[ i+1 ] = start[ i-1 ] + d[ i ]

所以最后累加每个人的QWQ得到最初答案

 


然后考虑往哪里加??
(1)如果你到达这个站点 i 的时候,最后一名乘客还没来
         也就是车等人,就没有必要加速了,因为对后面的站点无影响,而且加了也没大有用
(2)如果是人等车,还是可以考虑考虑的
         可能会对后面的站点造成影响

车每到达一个站点,就会有一部分人上车,一部分人下车
(不排除没人上下车的可能吧,不知道数据)
然后这些人就会产生等待时间和乘车时间,对答案产生影响
所以我们就找到站点中影响人数最多的那个,对ta加速就好了

                       sum[ i ] 前缀和维护到达站点i及之前站点的总人数
yx[ i ] (yingxiang影响)记录站点i可以影响到的最大站点编号

so,sum[ yx[ i ] ] - sum[ i ] 就是可以影响到的最多人数


这样人数多的就要放加速器
贪心就是这里

 


接下来枚举,一个一个找要放加速器的位置

每次使用加速器后站点的影响可能会发生改变,因此每次重算

然后寻找影响最大的站点,缩短路程,ans更新
然后更新arrive&start

最后输出答案

 

 

代码

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

const int maxn=1010,maxm=10010;
int n,m,k;
int d[maxn],arrive[maxn],start[maxn],last[maxn],yx[maxn],sum[maxn];
int ans,maxx=-1;
struct node
{
    int u,v,w;
}peo[maxm];

void chuli(int x)
{
    while(x)
    {
        --x;
        int goal;  //要加速的站点编号 
        maxx=-1;   //最大影响人数 
        yx[n-1]=yx[n]=n;
        for(int i=n-2;i>=1;i--)
        {
            if(arrive[i+1]<=last[i+1]) yx[i]=i+1;  //车等人,最多对后一个点产生影响 
            else  yx[i]=yx[i+1];  //人等车 
        }

        for(int i=1;i<n;i++)  //枚举可能使用加速器的站点(肯定不用考虑 
        {
            int kk=sum[yx[i]]-sum[i];
            if(kk>maxx&&d[i]>0)
            {
                maxx=kk;
                goal=i;
            }
        }
        
        ans-=maxx;  //人数即加速的时间 
        d[goal]--;
    
        for(int i=1;i<=n;i++)  //更新arrive&start 
        {
            start[i]=max(last[i],arrive[i]);
            arrive[i+1]=start[i]+d[i];
        }
    
    }
    return ;
}

int main()
{    
    n=read();m=read();k=read();
    
    for(int i=1;i<n;i++)
      d[i]=read();
      
    for(int i=1;i<=m;i++)
    {
        peo[i].w =read();
        peo[i].u =read();
        peo[i].v =read();
        sum[peo[i].v]++;   //到站人数 
        last[peo[i].u]=max(last[peo[i].u],peo[i].w );
    }
    
    arrive[1]=0;
    for(int i=1;i<=n;i++)
    {
        sum[i]+=sum[i-1];
        start[i]=max(last[i],arrive[i]);
        arrive[i+1]=start[i]+d[i];
    }

    for(int i=1;i<=m;i++)
    {
        ans+=(arrive[peo[i].v]-peo[i].w);
    }

    chuli(k);
    
    printf("%d\n",ans);
    
    return 0;
}

 

posted @ 2019-07-10 10:26  晔子  阅读(264)  评论(0编辑  收藏  举报