NOIP2011day2 观光公交(堆+贪心)

版权声明:我这种蒟蒻的文章,真正的大佬一般看不上的_(:з」∠)_ https://blog.csdn.net/Paulliant/article/details/82556540

题意

n 个景点, m 个游客,第 i 个游客在 T i 时间到达 A i 景点,要去 B i 景点。有一个公交车在 0 时刻在 1 号景点出现,从 i 号景点到 i + 1 号景点需要 D i 时间,从第 i 个景点去往第 i + 1 个景点必须保证所有出现在 A i 的人均上车(上下车不需时间)。现在有 k 个加速器,每个加速器可以使得某一个 D i 1 ,但不能小于 0 ,求所有游客从刚到景点到下车时间差值的和最小是多少。
1 n 1000
1 m 10000

思路

题目比较复杂,但所求还是比较清晰的,因为游客刚到景点的时间已经给定,所以只用求所有游客下车时间总和的最小值即可。我们单独分析在每个点使用加速器的效果,不难发现,当公交车不用等来的晚的游客时,这个效果可以抑制持续下去,直到遇到了一个来的和公交车一样晚,甚至更晚的游客,在这之后下车的游客便不受影响了。这样我们也不难发现一个贪心决策,先处理处一下连续影响的区间,按照下车人数从大到小排序,每弹出一个 [ l , r ] 决策是在 l 1 l 的路上用加速器,直到某一个点的人来的时间和公交车一样了,并把这个区间沿着这个点劈开;而当 D l 1 被加速成 0 时还没有遇到劈开,那就把 [ l + 1 , r ] 加入堆。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(register int i=(x);i<=(y);++i)
#define DOR(i,x,y) for(register int i=(x);i>=(y);--i)
#define N 1003
#define M 10003
typedef long long LL;
using namespace std; //S[i]表示目前公交车刚到i的时间 
int onbus[N],cnt[N],D[N],S[N],T[M],A[M],B[M];
int n,m,K;
struct node
{
    int l,r;  //使[l,r]中的乘客时间减少1 
    bool operator <(const node &_)const{return cnt[r]-cnt[l-1]<cnt[_.r]-cnt[_.l-1];}
};
priority_queue<node>q;

int main()
{
    scanf("%d%d%d",&n,&m,&K);
    FOR(i,1,n-1)scanf("%d",&D[i]);
    FOR(i,1,m)
    {
        scanf("%d%d%d",&T[i],&A[i],&B[i]);
        onbus[A[i]]=max(onbus[A[i]],T[i]);
        cnt[B[i]]++;
    }
    FOR(i,2,n)cnt[i]+=cnt[i-1];
    FOR(i,2,n)S[i]=max(S[i-1],onbus[i-1])+D[i-1];
    FOR(i,2,n)
        if(S[i]>onbus[i])
        {
            FOR(j,i,n)
                if(j==n||S[j]<=onbus[j])
                {
                    q.push((node){i,j});
                    i=j;
                    break;
                }
        }
    while(!q.empty()&&K>0)
    {
        node now=q.top();q.pop();
        int miner=min(K,D[now.l-1]),p=-1;
        FOR(i,now.l,now.r-1)
            if(S[i]-onbus[i]<miner)
            {
                miner=S[i]-onbus[i];
                p=i;
            }
        D[now.l-1]-=miner,K-=miner;
        FOR(i,now.l,now.r)S[i]=max(S[i-1],onbus[i-1])+D[i-1];
        if(~p)q.push((node){now.l,p}),q.push((node){p+1,now.r});
        else if(now.l<now.r)q.push((node){now.l+1,now.r});  //无法继续加速 
    }
    int ans=0;
    FOR(i,1,m)ans+=S[B[i]]-T[i];
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Paulliant/article/details/82556540
今日推荐