题目:https://www.luogu.com.cn/problem/P7913
我好菜啊,比赛的题现在才搞明白 qaq…
思路:
定义 i n in in、 o u t out out 数组, i n i in_i ini 表示在每一架飞机停在编号尽可能小的廊桥的前提下,第 i i i 号廊桥最多能停多少架国内飞机, o u t i out_i outi 同理。
很显然当国内有 j j j 个廊桥时,最多能停 ∑ i = 1 j i n i \sum_{i = 1}^{j}in_i ∑i=1jini 架飞机,国际航班同理。
于是我们就可以先预处理出 i n i in_i ini 和 o u t i out_i outi,然后求一遍前缀和,于是 i n i in_i ini 就表示成了国内有 i i i 个廊桥时最多能停的飞机数, o u t i out_i outi 同理。
最后 O ( n ) O(n) O(n) 枚举一遍,就求出答案啦!
完结撒花
别急,我们还要考虑怎么预处理 i n i in_i ini、 o u t i out_i outi。
用一个小根堆 Q Q Q 维护在廊桥内的航班,小根堆 i d id id 来维护当前空余的廊桥。
当一架飞机的抵达时间大于了在廊桥内离开时间最早的飞机,就让 Q Q Q 的堆顶弹出,再把这架飞机的编号塞到 i d id id 里。
当 i d id id 不为空时,就把 i d id id 的堆顶和当前飞机的离开时间塞到 Q Q Q 里,意思是让当前飞机停到当前闲置的编号最小的廊桥( i d id id 的堆头总是当前闲置的编号最小的廊桥)。再将这个廊桥的贡献加一,然后 i d id id 的堆顶就可以扔掉了。
光说不好懂,可以再借助代码理解一下。
AC code:
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
template<class T>inline void read(T &s){
int f=1; s=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f*=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
s*=f;
}
#define MAXN (int)(1e5+10)
#define debug cout<<"I f*** **F\n";
int n,m1,m2,in[MAXN],out[MAXN];
struct node{
int beg,end;
inline void Read(){read(beg),read(end);}
}a[MAXN],b[MAXN];
struct Node{
int ID,end;
bool operator<(const Node&x)const{
return x.end<end;
}
};
priority_queue<Node> Q;
priority_queue<int,vector<int>,greater<int> >id;
void init(){
while(!id.empty()) id.pop();
while(!Q.empty()) Q.pop();
for(int i=1;i<=n;i++) id.push(i);
}
void solve1(){
for(int i=1;i<=m1;i++){
while(Q.size()&&Q.top().end<a[i].beg)
id.push(Q.top().ID),Q.pop();
if(id.size())
Q.push((Node){id.top(),a[i].end}),
in[id.top()]++,id.pop();
}
}
void solve2(){
for(int i=1;i<=m2;i++){
while(Q.size()&&Q.top().end<b[i].beg)
id.push(Q.top().ID),Q.pop();
if(id.size())
Q.push((Node){id.top(),b[i].end}),
out[id.top()]++,id.pop();
}
}
bool cmp(const node&x,const node&y){return x.beg<y.beg;}
signed main(){
read(n),read(m1),read(m2);
for(int i=1;i<=m1;i++) a[i].Read();
for(int i=1;i<=m2;i++) b[i].Read();
sort(a+1,a+m1+1,cmp);sort(b+1,b+m2+1,cmp);
int ans=-114514;
init(),solve1(); init(),solve2();
for(int i=1;i<=n;i++)
in[i]+=in[i-1],out[i]+=out[i-1];
for(int i=0;i<=n;i++)
ans=max(ans,in[i]+out[n-i]);
printf("%d",ans);
return 0;
}
完结撒花~~