1. 程式人生 > 其它 >[CSP-S 2021]廊橋分配

[CSP-S 2021]廊橋分配

廊橋分配

題面

當一架飛機抵達機場時,可以停靠在航站樓旁的廊橋,也可以停靠在位於機場邊緣的遠機位。乘客一般更期待停靠在廊橋,因為這樣省去了坐擺渡車前往航站樓的周折。然而,因為廊橋的數量有限,所以這樣的願望不總是能實現。

機場分為國內區和國際區,國內航班飛機只能停靠在國內區,國際航班飛機只能停靠在國際區。一部分廊橋屬於國內區,其餘的廊橋屬於國際區。

\(L\) 市新建了一座機場,一共有 \(n\) 個廊橋。該機場決定,廊橋的使用遵循“先到先得”的原則,即每架飛機抵達後,如果相應的區(國內/國際)還有空閒的廊橋,就停靠在廊橋,否則停靠在遠機位(假設遠機位的數量充足)。該機場只有一條跑道,因此不存在兩架飛機同時抵達的情況。

現給定未來一段時間飛機的抵達、離開時刻,請你負責將 \(n\) 個廊橋分配給國內區和國際區,使停靠廊橋的飛機數量最多。

\(1\leq n \leq 10^5,m_1、m_2\geq 1,m_1+m_2\leq 10^5\)

\(m_1\)\(m_2\) 分別表示國內航班的數量與國際航班的數量。

分析

觀察資料範圍,顯然我們大概需要一個 \(O(nlogn)\) 的做法,考慮怎麼做。

原題面中本來附有一個表格,從表格統計的形式來看,猜測最後的答案統計是 \(O(n)\) 的,即我們需要求出分配 \(x\) 個廊橋給國內與國外能夠停靠的飛機數量。

發現每個廊橋實際上相互之間不干擾,我們可以把飛機分成若干個組,每個組由同一個廊橋包辦。

於是我們可以維護這樣一個過程:

  • 如果存在廊橋空閒,取用編號最小的空閒廊橋(儘量少的廊橋儘量多的值,故編號要選最小)。

  • 若不存在,新開一組,增加一個廊橋。

以上過程我們可以用兩個小根堆維護,一個維護目前不空閒的廊橋的狀態,一個維護空閒廊橋的編號即可。

CODE

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w*=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w;
}
struct Brige{
	int t,num;
	friend bool operator < (const Brige &X,const Brige &Y ){
		return X.t>Y.t; //小根 
	}
};
struct node{ int st,ed; }A[N],B[N]; 
struct Airport{ int a,b; }dp[N],sum[N];
int n,ans;
int x,y;
priority_queue<Brige> q;
priority_queue<int,vector<int>,greater<int> > id; //小根堆,儲存目前空餘編號 
inline bool cmp(node a,node b) { return a.st<b.st; }
int main()
{
//	freopen("airport.in","r",stdin);
//	freopen("airport.out","w",stdout);
	n=read(),x=read(),y=read();
	for(register int i=1;i<=x;i++){
		A[i].st=read(),A[i].ed=read();
	}
	for(register int i=1;i<=y;i++){ 
		B[i].st=read(),B[i].ed=read(); 
	} 
	sort(A+1,A+x+1,cmp),sort(B+1,B+y+1,cmp); 
	int cnt=0; 
	for(register int i=1;i<=x;i++){ 
		while(q.size()){ 
			Brige now=q.top(); 
			if(now.t>A[i].st) break; 
			q.pop(); //空閒,彈出 
			id.push(now.num); //第num號橋空閒 
		}
		if(id.size()){ //有橋空閒 
			int now=id.top(); id.pop();
			dp[now].a++; //使用第now號橋飛機停泊量++ 
			q.push((Brige){A[i].ed,now});
		}
		else{ //無橋空閒 
			cnt++; //新建立一個橋
			dp[cnt].a++;
			q.push((Brige){A[i].ed,cnt});
		} 
	}
	cnt=0;
	while(!q.empty()) q.pop();
	while(!id.empty()) id.pop();
	for(register int i=1;i<=y;i++){
		while(q.size()){
			Brige now=q.top();
			if(now.t>B[i].st) break;
			q.pop(); //空閒,彈出 
			id.push(now.num); //第num號橋空閒 
		}
		if(id.size()){ //有橋空閒 
			int now=id.top(); id.pop();
			dp[now].b++; //使用第now號橋飛機停泊量++ 
			q.push((Brige){B[i].ed,now});
		}
		else{ //無橋空閒 
			cnt++; //新建立一個橋
			dp[cnt].b++;
			q.push((Brige){B[i].ed,cnt});
		} 
	}
	for(register int i=1;i<=n;i++) sum[i].a=sum[i-1].a+dp[i].a;
	for(register int i=1;i<=n;i++) sum[i].b=sum[i-1].b+dp[i].b;
	for(register int i=0;i<=n;i++){
		ans=max(ans,sum[i].a+sum[n-i].b);
	}
	printf("%d\n",ans); 
	return 0;
}
作者: ╰⋛⋋⊱๑落葉๑⊰⋌⋚╯

-------------------------------------------

海到無邊天作岸,山登絕頂我為峰!