【NOIP2011】观光公交

题解:贪心策略----使用一次加速器,只会对当前第i站车上的乘客以及已经到第i+1站的乘客做出贡献,每次贪心寻找到最优的站台加速即可。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
#include<cstring>
#include<queue>
#include<stack>
#define MAXN 200010
#define LL long long int
using namespace std;
const int INF=1e9;
const int EPS=1e-8;
struct node{
    int T;
    int A;
    int B;
}a[MAXN];
int n,m,k;
int ans;
int d[MAXN];//从i到i+1的时间
int t[MAXN];//到达i的时刻
int f[MAXN];//最晚到达i的乘客的时刻
int g[MAXN];//在i车站加速最大影响到的车站
int sum[MAXN];//前i个车站下车的人数
int main()
{
    freopen("1.in","r",stdin);
    //    freopen("1.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n-1;i++)
        scanf("%d",&d[i]);
    for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a[i].T,&a[i].A,&a[i].B);
            f[a[i].A]=max(f[a[i].A],a[i].T);//求出最晚到的乘客时刻
            sum[a[i].B]++;
        }
    for(int i=2;i<=n;i++)
        sum[i]+=sum[i-1];//前缀和求人数
    t[1]=0;
    for(int i=2;i<=n;i++)
        t[i]=max(t[i-1],f[i-1])+d[i-1];//当前到达i的时刻
    for(int i=1;i<=m;i++)
        ans+=t[a[i].B]-a[i].T;//旅游时间
    while(k>0)
        {
            g[n]=n;
            g[n-1]=n;
            for(int i=n-2;i;i--)
                {
                    if(t[i+1]<=f[i+1])//如果下一站的需要等待的乘客到达时间大于到达的时刻,那么在i+1车站之后站下车的乘客不会收到在i加速的影响
                        g[i]=i+1;
                    else g[i]=g[i+1];
                }
            int maxl=0,j;
            for(int i=1;i<=n;i++)
                if(sum[g[i]]-sum[i]>maxl&&d[i]>0)//找到影响最多人的车站,贪心策略
                    maxl=sum[g[i]]-sum[i],j=i;
            if(!maxl) break;
            ans-=maxl;
            d[j]--;//加速
            k--;//少了一个
            t[1]=0;
            for(int i=2;i<=n;i++)
                t[i]=max(t[i-1],f[i-1])+d[i-1];//再次贪心
        }
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2017-08-01 11:39  楼主大大  阅读(614)  评论(15编辑  收藏  举报