#EXJ1004. 机场设施使用优化

ID: 255传统题2000ms512MiB尝试: 3已通过: 1难度: 10

机场设施使用优化

时间限制: 1000 ms 内存限制: 524288 KB

【题目描述】

当一架飞机抵达机场时,可以停靠在航站楼旁的廊桥,也可以停靠在位于机场边缘的远机位。乘客一般更期待停靠在廊桥,因为这样省去了坐摆渡车前往航站楼的周折。

然而,因为廊桥的数量有限,所以这样的愿望不总是能实现。

机场分为国内区和国际区,国内航班飞机只能停靠在国内区,国际航班飞机只能停靠在国际区。一部分廊桥属于国内区,其余的廊桥属于国际区。

L 市新建了一座机场,一共有 nn 个廊桥。该机场决定,廊桥的使用遵循“先到先得”

的原则,即每架飞机抵达后,如果相应的区(国内/国际)还有空闲的廊桥,就停靠在廊桥,否则停靠在远机位(假设远机位的数量充足)。该机场只有一条跑道,因此不存在两架飞机同时抵达的情况。

现给定未来一段时间飞机的抵达、离开时刻,请你负责将 nn 个廊桥分配给国内区和国际区,使停靠廊桥的飞机数量最多。

【输入】

输入的第一行包含 33 个正整数 nn, m_1m1, m_2m2 分别表示廊桥的个数、国内航班飞机的数量、国际航班飞机的数量。

接下来 m_1m1 行是国内航班的信息,第 ii 行包含 22 个正整数 a_{1,i}a1**,i​**, b_{1,i}b1**,i​**,分别表示一架国内航班飞机的抵达、离开时刻。

接下来 m_2m2 行是国际航班的信息,第 ii 行包含 22 个正整数 a_{2,i}a2**,i​**, b_{2,i}b2**,i​**,分别表示一架国际航班飞机的抵达、离开时刻。

每行的多个整数由空格分隔。

【输出】

输出一个正整数,表示能够停靠廊桥的飞机数量的最大值。

【输入样例】

3 5 4
1 5
3 8
6 10
9 14
13 18
2 11
4 15
7 17
12 16

Copy

【输出样例】

7

Copy

【提示】

【样例 1 解释】

在图中,我们用抵达、离开时刻的数对来代表一架飞机,如 (11, 55) 表示时刻 11 抵达、时刻 55 离开的飞机;用 √ 表示该飞机停靠在廊桥,用 ××表示该飞机停靠在远机位。

我们以表格中阴影部分的计算方式为例,说明该表的含义。在这一部分中,国际区有 22 个廊桥,44 架国际航班飞机依如下次序抵达:13135991056次航班

  1. 首先 (22, 1111) 在时刻 22 抵达,停靠在廊桥
  2. 然后 (44, 1515) 在时刻 44 抵达,停靠在另一个廊桥
  3. 接着 (77, 1717) 在时刻 77 抵达,这时前 22 架飞机都还没离开、都还占用着廊桥,而国际区只有 22 个廊桥,所以只能停靠远机位
  4. 最后 (1212, 1616) 在时刻 1212 抵达,这时 (22,1111) 这架飞机已经离开,所以有 11 个空闲的廊桥,该飞机可以停廊桥

根据表格中的计算结果,当国内区分配 22 个廊桥、国际区分配 11 个廊桥时,停靠廊桥的飞机数量最多,一共 235 架。

【样例 2 输入】

2 4 6
20 30
40 50
21 22
41 42
1 19
2 18
3 4
5 6
7 8
9 10

Copy

【样例 2 输出】

4

Copy

【样例 2 解释】

当国内区分配 22 个廊桥、国际区分配 00 个廊桥时,停靠廊桥的飞机数量最多,一共44 架,即所有的国内航班飞机都能停靠在廊桥。

需要注意的是,本题中廊桥的使用遵循“先到先得”的原则,如果国际区只有 11 个廊桥,那么将被飞机 (11, 1919) 占用,而不会被 (33, 44)、(55, 66)、(77, 88)、(99, 1010) 这44 架飞机先后使用。

【数据范围】

对于 20% 的数据,1 ≤ n ≤ 1001n100, 1 ≤ m_1 + m_2 ≤ 1001m1+m2100

对于 40% 的数据,1 ≤ n ≤ 50001n5000, 1 ≤ m_1 + m_2 ≤ 50001m1+m25000

对于 100% 的数据,1 ≤ n ≤ 1000001n100000, 1 ≤ m_1 + m_2 ≤ 1000001m1+m2100000

所有 a_{1,i}a1**,i​**, b_{1,i}b1**,i​**, a_{2,i}a2**,i​**, b_{2,i}b2**,i​** 为数值不超过 10^8108 的互不相同的正整数。

保证 ∀_i ∈ [1, n]i∈**[1,n], a_{1,i} < b_{1,i}, a_{2,i} < b_{2,i}a1,i​**<b1**,i​**,a2**,i​**<b2**,i​**。

本题目评测默认开启-O2O2

进入正题(上代码)

代码如下,这边建议不要直接抄袭,可以借鉴 注解在代码中展示

第一种AC:95%,错误一个测试点

#include<set>
#include<cstdio>
#include<algorithm>
#define db double
#define U unsigned
#define ll long long
#define lb long double
#define ull unsigned long long
#define Me(a,b) memset(a,b,sizeof(a))
template<typename _T> _T abs(_T a){ return a>0?a:-a; }
template<typename _T> _T max(_T a,_T b){ return a>b?a:b; }
template<typename _T> _T min(_T a,_T b){ return a<b?a:b; }
template<typename _T> void print(_T x){ if(x<0) putchar('-'),x=-x;
	if(x>9) print(x/10); putchar(x%10+48); return; }
#define EPS (1e-7)
#define INF (0x7fffffff)
#define LLINF (0x7fffffffffffffff)
#define maxn 100039
#define maxm
#define MOD
using namespace std;
#define Type int
Type read(){
	char c=getchar(); Type sum=0; int flag=0;
	while((c<'0'||c>'9')&&c!='-') c=getchar(); if(c=='-') c=getchar(),flag=1;
	while('0'<=c&&c<='9'){ sum=(sum<<1)+(sum<<3)+(c^48); c=getchar(); }
	if(flag) return -sum; return sum;
}
int n,m1,m2,f1[maxn],f2[maxn];
struct Plane{
	int st,en,num;
	bool operator < (const Plane x) const{ return this->st < x.st; }
}a1[maxn],a2[maxn];
int cmp(Plane x,Plane y){ return x.st<y.st; }
set<Plane> s; int flag[maxn];
void init(Plane a[],int f[],int m){
	s.clear(); int i,now=0; Plane tmp; set<Plane>::iterator it; for(i=1;i<=m;i++) s.insert(a[i]);
	while(!s.empty()){
		tmp=*s.begin(); s.erase(s.begin()); now++; f[now]=1;
		while(1){
			tmp.st=tmp.en; it=s.upper_bound(tmp);
			if(it==s.end()) break; f[now]++; s.erase(it); tmp=*it;
		}
	} return;
}
int maxx;
int main(){
	//freopen("airport.in","r",stdin);
	//freopen(".out","w",stdout);
	n=read(); m1=read(); m2=read(); int i;
	for(i=1;i<=m1;i++) a1[i].st=read(),a1[i].en=read(),a1[i].num=i; init(a1,f1,m1);
	for(i=1;i<=m2;i++) a2[i].st=read(),a2[i].en=read(),a2[i].num=i; init(a2,f2,m2);
	//for(i=1;i<=m1;i++) print(f1[i]),putchar(' '); putchar('\n');
	//for(i=1;i<=m1;i++) print(f2[i]),putchar(' '); putchar('\n');
	for(i=1;i<=m1;i++) f1[i]+=f1[i-1]; for(i=1;i<=m2;i++) f2[i]+=f2[i-1];
	for(i=0;i<=n;i++) if(f1[i]+f2[n-i]>maxx) maxx=f1[i]+f2[n-i];
	print(maxx); return 0;
}

换种思路重新定义 AC:100%(accept)

#include <bits/stdc++.h>
#include <cstdio>
#include <functional>
#define P pair <int,int>
using namespace std;

struct node {
	int a, b;
} fc[100010], fa[100010];

bool cmp(node a, node b) {
	return a.a < b.a;
}
int n, m1, m2, maxn = -1, ans1[100010], ans2[100010];

void check() {
	priority_queue<int, vector<int>, greater<int> > q;//维护廊桥编号
	priority_queue<P, vector<P>, greater<P> > p;//维护飞机出站时间和停靠的廊桥的编号
	for (int i = 1; i <= n; i++) {
		q.push(i);//一开始所有廊桥都处于空闲状态,把所有廊桥加入队列。
	}
	for (int i = 1; i <= m1; i++) {
		int s = fc[i].a;//该架飞机入站时间
		while (!p.empty() && s > p.top().first) {
			//弹出已经飞走的飞机并把它所停课的廊桥加入队列
			q.push(p.top().second);
			p.pop();
		}
		if (!q.empty()) {
			int id = q.top();
			q.pop();//取编号最小的廊桥停靠
			ans1[id]++;//该编号的廊桥产生的贡献加一
			p.push(P(fc[i].b, id));
		}
	}
	while (!q.empty())
		q.pop();
	while (!p.empty())
		p.pop();
	//清空队列
	for (int i = 1; i <= n; i++) {
		q.push(i);
	}
	//同上
	for (int i = 1; i <= m2; i++) {
		int s = fa[i].a;
		while (!p.empty() && s > p.top().first) {
			q.push(p.top().second);
			p.pop();
		}
		if (!q.empty()) {
			int id = q.top();
			q.pop();
			ans2[id]++;
			p.push(P(fa[i].b, id));
		}
	}
	for (int i = 1; i <= n; i++) {
		ans1[i] += ans1[i - 1];
		ans2[i] += ans2[i - 1];
	}
	//前缀和数组维护每种分配方案产生的答案
	return;
}

int main() {
	scanf("%d%d%d", &n, &m1, &m2);
	for (int i = 1; i <= m1; i++) {
		scanf("%d%d", &fc[i].a, &fc[i].b);
	}
	for (int i = 1; i <= m2; i++) {
		scanf("%d%d", &fa[i].a, &fa[i].b);
	}
	sort(fc + 1, fc + 1 + m1, cmp);
	sort(fa + 1, fa + 1 + m2, cmp);
	check();
	//统计答案
	for (int i = 0; i <= n; i++) {
		if (ans1[i] + ans2[n - i] > maxn) {
			maxn = ans1[i] + ans2[n - i];
		}
	}
	printf("%d", maxn);
	return 0;
}