Logo __vector__ 的博客

博客

CSP-S2021 题解

...
__vector__
2025-12-01 12:55:47

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-07-26 22:51:46

题外话

这是某蒟蒻为了 CSP-S2022 不爆零做的一点挣扎。

廊桥分配

做法

一个简单的思路就是枚举分配给国内航班和国际航班的航班数量,然后每枚举一种情况 $O(n)$ 计算答案,最后取最大值,总复杂度 $O(n^2)$。

想一想能不能对计算答案进行优化。

显然,设分配了 $i$ 个廊桥,那么答案等于这 $i$ 个廊桥分别有多少飞机停靠。

一个比较显然的结论是,当廊桥数量增加时,如果强制飞机进入编号最小的空闲廊桥,那么原来去哪个廊桥的飞机还去哪个廊桥。

所以,可以先预处理出在假设廊桥充足的情况下,每个廊桥有多少飞机停靠。

然后做个前缀和,前缀和数组第 $i$ 个元素表示如果有 $i$ 个廊桥,那么答案是多少。

枚举分配廊桥数量取最大值就行了。

Code

#include <bits\/stdc++.h>
using namespace std;
namespace Main
{
    const int maxn=1e5+5;
    int n,m1,m2;
    struct Plane
    {
        int a,b;
    }pl[maxn],pl2[maxn];
    bool cmp(Plane a,Plane b)
    {
        return a.a<b.a;
    }
    int qzh[maxn],qzh2[maxn];
    void calc1()
    {
        priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> lk;
        \/\/待离开飞机队列
        \/\/pair的第一个元素是离开时间,第二个是占用的廊桥编号
        priority_queue<int,vector<int>,greater<int>> lq;
        \/\/空闲廊桥队列
        for(int i=1;i<=n;i++)
        {
            lq.push(i);
        }\/\/初始所有廊桥都是空的
        for(int i=1;i<=m1;i++)
        {
            while(!lk.empty()&&lk.top().first<pl[i].a)\/\/将第 i 架飞机到达前已经离开的飞机清除并释放廊桥
            {
                lq.push(lk.top().second);
                lk.pop();
                \/\/飞机离开,释放廊桥
            }
            if(lq.empty())continue;
            int used=lq.top();\/\/当前飞机使用的廊桥编号
            qzh[used]++;
            lq.pop();
            lk.push(make_pair(pl[i].b,used));
        }
        for(int i=1;i<=n;i++)
        {
            qzh[i]=qzh[i-1]+qzh[i];
        }
    }
    void calc2()
    {
        priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> lk;
        \/\/待离开飞机队列
        \/\/pair的第一个元素是离开时间,第二个是占用的廊桥编号
        priority_queue<int,vector<int>,greater<int>> lq;
        \/\/空闲廊桥队列
        for(int i=1;i<=n;i++)
        {
            lq.push(i);
        }\/\/初始所有廊桥都是空的
        for(int i=1;i<=m2;i++)
        {
            while(!lk.empty()&&lk.top().first<pl2[i].a)\/\/将第 i 架飞机到达前已经离开的飞机清除并释放廊桥
            {
                lq.push(lk.top().second);
                lk.pop();
                \/\/飞机离开,释放廊桥
            }
            if(lq.empty())continue;
            int used=lq.top();\/\/当前飞机使用的廊桥编号
            qzh2[used]++;
            lq.pop();
            lk.push(make_pair(pl2[i].b,used));
        }
        for(int i=1;i<=n;i++)
        {
            qzh2[i]=qzh2[i-1]+qzh2[i];
        }
    }
    void main()
    {
        scanf("%d%d%d",&n,&m1,&m2);
        for(int i=1;i<=m1;i++)
        {
            scanf("%d%d",&pl[i].a,&pl[i].b);
        }
        for(int i=1;i<=m2;i++)
        {
            scanf("%d%d",&pl2[i].a,&pl2[i].b);
        }
        sort(pl+1,pl+m1+1,cmp);
        sort(pl2+1,pl2+m2+1,cmp);
        calc1();
        calc2();
        int ans=0;
        for(int i=0;i<=n;i++)
        {
            ans=max(ans,qzh[i]+qzh2[n-i]);
        }
        printf("%d",ans);
    }
}
int main()
{
    Main::main();
    return 0;
}

其他 3 题

还没做。

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。