P7913 [CSP-S 2021] 廊桥分配 题解

题目: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
#include
#include
#include
#include
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;
} 

完结撒花~~

你可能感兴趣的:(题解,c++,算法,数据结构,csp)