链接:
题意:
有 \(m_1\) 架飞机和 \(m_2\) 架飞机停在两个机场,每架飞机有到达和离开的时间,要将 \(n\) 个廊桥分给两个机场,每个廊桥同一时刻只能停一架飞机,需要最大化能够停在这 \(n\) 个廊桥的飞机数量。
分析:
一个容易想到的思路是算出每个机场有 \(i\) 个廊桥时能够停下的飞机数量,最后 \(O(n)\) 比较一遍。我们思考可以想到一个性质,就是对于每架飞机,它所能停靠的编号最小的廊桥是一定的,也就是说,不管分配了多少廊桥,每架飞机该在哪个廊桥停就一定会在哪个廊桥停,只是廊桥数量不足时会表现为停不了。
考虑一下会发现这个东西很对,所以我们先求出每架飞机所能停靠的编号最小的廊桥。
对于每架飞机,只需要找到当前空闲的廊桥中编号最小的,可以用一个优先队列维护。
同时还要维护停有飞机的廊桥,因为要维护一个飞机到达时哪些廊桥会变空,同样使用优先队列。
算法:
先把飞机按到达时间排序,然后用两个优先队列维护空着的廊桥和非空的廊桥,得到每个飞机所能停靠的编号最小的廊桥,然后做一个前缀和就能得到每个机场有 \(i\) 个廊桥时能够停下的飞机数量,最后得到答案。
代码:
#include<bits/stdc++.h>
using namespace std;
#define mkp make_pair
#define int long long
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){p=p*10+c-'0';c=getchar();}
return p*f;
}
const int N=1e5+5;
int n,m1,m2,ans1[N],ans2[N],ans;
struct plane{int x,y;}a[N],b[N];
bool cmp(plane x,plane y){return x.x<y.x;}
priority_queue<pair<int,int> >q;//非空
priority_queue<int>p;//空
signed main(){
freopen("airport.in","r",stdin);
freopen("airport.out","w",stdout);
n=in,m1=in,m2=in;
for(int i=1;i<=m1;i++)
a[i].x=in,a[i].y=in;
for(int i=1;i<=m2;i++)
b[i].x=in,b[i].y=in;
sort(a+1,a+1+m1,cmp);
sort(b+1,b+1+m2,cmp);
for(int i=1;i<=n;i++)p.push(-i);
for(int i=1;i<=m1;i++){
int s=a[i].x,t=a[i].y;
while(!q.empty()&&-q.top().first<s){p.push(-q.top().second);q.pop();}
if(!p.empty()){int tp=-p.top();q.push(mkp(-t,tp));ans1[tp]++;p.pop();}
}
while(!q.empty())q.pop();
while(!p.empty())p.pop();
for(int i=1;i<=n;i++)p.push(-i);
for(int i=1;i<=m2;i++){
int s=b[i].x,t=b[i].y;
while(!q.empty()&&-q.top().first<s){p.push(-q.top().second);q.pop();}
if(!p.empty()){int tp=-p.top();q.push(mkp(-t,tp));ans2[tp]++;p.pop();}
}
for(int i=1;i<=n;i++)
ans1[i]+=ans1[i-1],
ans2[i]+=ans2[i-1];
for(int i=0;i<=n;i++)
ans=max(ans,ans1[i]+ans2[n-i]);
cout<<ans;
return 0;
}
题外话:
不算很难,实现也很简单,可惜了
三分是错解,一个单增加一个单减可能是任意函数。要构造卡三分的数据非常简单。