鏈接:
題意:
有 \(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;
}
題外話:
不算很難,實現也很簡單,可惜了
三分是錯解,一個單增加一個單減可能是任意函數。要構造卡三分的數據非常簡單。