[CSP-S 2021] 廊桥分配

戳我跳转题面

题意

一共有 n 个廊桥,全部分配给互相独立的两组。第一组有 m1 个区间 [li,ri], 第二组有 m2 个区间 [ai,bi](互相独立),一旦有廊桥空着,就会将 i 区间覆盖于总区间。问一共能满足多少个区间。

思路

45pts

由于两组的处理方法几乎一样,在这里只举第一组的例子。

首先最重要的是要排个序,因为“先到先得”原则,自是按照左端点排序。
然后暴力枚举分配给第一组的廊桥个数 i,接着就可以 O(1) 求出第二组的廊桥数量 j。再下去就模拟一下飞机的入场,用一个优先队列来存放正在使用的廊桥数量。如果廊桥中的飞机在当前飞机 k 到达之前就应该走了,那么就将这架飞机弹出队列。最后看一下当前飞机能否入场,可以的话将飞机插入队列。答案就是枚举过程中能够停靠的飞机的总数的 max

View
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <ll, ll> P;

const int N = 100010;
struct node
{
	ll arr, lef;
};
ll n, m1, m2;
ll ans;
P p[2][N];

bool operator < (node a, node b) {return a.lef > b.lef;}

int main()
{
	scanf("%lld%lld%lld", &n, &m1, &m2);
	for (int i = 1; i <= m1; i++) scanf("%lld%lld", &p[0][i].first, &p[0][i].second);
	for (int i = 1; i <= m2; i++) scanf("%lld%lld", &p[1][i].first, &p[1][i].second);
	sort(p[0] + 1, p[0] + m1 + 1);
	sort(p[1] + 1, p[1] + m2 + 1);
	for (int dom = 1; dom <= n; dom++)
	{
		ll tmp;
		tmp = 0;
		priority_queue <node> q, q2;
		for (int i = 1; i <= m1; i++)
		{
			ll arr;
			arr = p[0][i].first;
			while (!q.empty() && q.top().lef <= arr) q.pop();
			if (q.size() < dom) q.push({arr, p[0][i].second}), tmp++;
		}
		for (int i = 1; i <= m2; i++)
		{
			ll arr;
			arr = p[1][i].first;
			while (!q2.empty() && q2.top().lef <= arr) q2.pop();
			if (q2.size() < n - dom) q2.push({arr, p[1][i].second}), tmp++;
		}
		ans = max(ans, tmp);
	}
	printf("%lld\n", ans);
	return 0;
}

100pts

也就是相比45分暴力多了那么一点点优化。

排序是必须的,所以先按左端点排序。

然后我们分析一下暴力的复杂度,排序 O(m1·logm1+m2·logm2),枚举 O(n2·(m1+m2)),而这个 O(n2) 才是最大的问题。

其实我们可以设置 res1,i,res2,i 分别表示第一组、第二组给 i 个廊桥的最大停靠飞机数量。

最后一定要先加前缀和,然后 ans=max(res1,i,res2,ni)


Talk is cheap, show me the code.

View
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <ll, ll> P;

const int N = 100010;
ll n, m1, m2;
ll res[N], res2[N];
P a[N], b[N];
priority_queue <ll, vector <ll>, greater <ll> > q, q2;
priority_queue <P, vector <P>, greater <P> > le, le2;

bool cmp(P x, P y) {return x.first < y.first;}

int main()
{
	scanf("%lld%lld%lld", &n, &m1, &m2);
	for (int i = 1; i <= m1; i++) scanf("%lld%lld", &a[i].first, &a[i].second);
	for (int i = 1; i <= m2; i++) scanf("%lld%lld", &b[i].first, &b[i].second);
	sort(a + 1, a + m1 + 1, cmp);
	sort(b + 1, b + m2 + 1, cmp);
	for (int i = 1; i <= n; i++) q.push(i), q2.push(i);	
	for (int i = 1; i <= m1; i++)
	{
		while (!le.empty() && le.top().first < a[i].first)
		{
			q.push(le.top().second);
			le.pop();
		}
		if (q.empty()) continue;
		res[q.top()]++;
		le.push({a[i].second, q.top()}), q.pop();
	}
	for (int i = 1; i <= m2; i++)
	{
		while (!le2.empty() && le2.top().first < b[i].first)
		{
			q2.push(le2.top().second);
			le2.pop();
		}
		if (q2.empty()) continue;
		res2[q2.top()]++;
		le2.push({b[i].second, q2.top()}), q2.pop();
	}
	for (int i = 1; i <= n; i++) res[i] += res[i - 1];
	for (int i = 1; i <= n; i++) res2[i] += res2[i - 1];
	ll ans;
	ans = 0;
	for (int i = 0; i <= n; i++) ans = max(ans, res[i] + res2[n - i]);
	printf("%lld\n", ans);
	return 0;
}

都看到这里了,点个关注再走呗 qwq

posted @   Faking  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示