题解 P5661 【公交换乘【民间数据】】

· · 题解

2019CSP-J第二题,大概是考场上遇到突发性脑残,相处了一种丧心病狂做法(官方数据只能拿80分):

我在CSP复赛的时候,做这一题没想太多,竟然不知道就是一道队列的题目。但是,我使用了一种丧心病狂的做法

首先,借助C++ STL的优势,我开了1000个小根堆(其实每一个小根堆就是一个价格的桶),然后每一次看价格比公交车大的桶,最后选出时间最小有符合题意的一个,时间复杂度上限大约是是O(n log(n/price)*price)。

行吧,别的话不多说,上代码:

#include<queue>
#include<cstdio>
using namespace std;
priority_queue<int,vector<int>,greater<int> > q[1010];
int T,t,a,b,w,ans,mx;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&w,&a,&b);
        if(a>mx) mx=a;
        if(w)
        {
            w=0;
            t=0x7fffffff;
            for(int i=a;i<=mx;i++)
            {
                while(!q[i].empty())
                {
                    if(b-q[i].top()<=45)
                    {
                        if(q[i].top()<t)
                        {
                            t=q[i].top();
                            w=i;
                        }
                        break;
                    }
                    else q[i].pop();
                }
            }
            if(w) q[w].pop();
            else ans+=a;
        }
        else
        {
            q[a].push(b);
            ans+=a;
        }
    }
    printf("%d",ans);
    return 0;
}

更新:2019.12.8

但是这种做法只能拿80分!

其实,我们不需要使用小根堆,因为题目中有说到这么一句话:

我们保证出行记录是按照开始乘车的时间顺序给出的,且不会有两次乘车记录出现在同一分钟。

根据上面的代码的思路,我们是先找时间最少的那一个,然后看行不行,在继续往后看。如果利用了这一点,我们可以把小根堆换成普通队列,因为队首的那一个元素肯定是那种价格中时间最小的。

所以,这样子的时间复杂度上线就是O(n*price),正常都可以AC这一道题目。

好了,上代码:

#include<queue>
#include<cstdio>
using namespace std;
queue<int> q[1010];
int T,t,a,b,w,ans,mx;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&w,&a,&b);
        if(a>mx) mx=a;
        if(w)
        {
            w=0;
            t=0x7fffffff;
            for(int i=a;i<=mx;i++)
            {
                while(!q[i].empty())
                {
                    if(b-q[i].front()<=45)
                    {
                        if(q[i].front()<t)
                        {
                            t=q[i].front();
                            w=i;
                        }
                        break;
                    }
                    else q[i].pop();
                }
            }
            if(w) q[w].pop();
            else ans+=a;
        }
        else
        {
            q[a].push(b);
            ans+=a;
        }
    }
    printf("%d",ans);
    return 0;
}

最后插入一则广告:本蒟蒻2019CSP-J只考了380分,因为第二题只拿了80分(v_v),希望大家吸取我的教训,争取AK明年的CSP!