首页 > 其他分享 >CSP-S 2021 廊桥分配

CSP-S 2021 廊桥分配

时间:2024-10-04 15:38:59浏览次数:1  
标签:飞机 q2 int m1 2021 m2 廊桥 CSP

2021年的提高组第一题

学校模拟测试的时候居然想到了AC的代码(((bushi

luogu P7913

题目意思

  大体意思就是有n个廊桥,m1起国内航班,m2起国际航班,国内区和国际区是分开的,把n个廊桥分到两个区,飞机想要尽可能的停在廊桥处,而不停在远机处,每架飞机都有各自的起降时间,廊桥按到达顺序供给飞机,问怎么分廊桥可使得停在廊桥的飞机最多?

  数据范围:1≤n≤105,m1,m2≥1,m1+m2≤105,ai<bi≤108

思路

  因为题目中说廊桥是按飞机抵达的先后顺序分配的,我先想到了一个暴力思路:就是枚举分给国内的廊桥的个数(则分给国外的廊桥个数为n-i),再去枚举国内国外能有多少架飞机可以停在廊桥,取和的最大值,这个思路的复杂度在不优化的情况下大概是O(n^2(m1+m2)),这个复杂度一眼就知道会炸,大概只能过前20%的数据

  接着,我否定了我上一个暴力思路后又想出了更好的一个暴力思路(别问我为啥老想暴力思路,因为正解也不是那么容易能思考出来的,这个离着我的AC思路已经很近了):我们不如先假设廊桥有无数个,去遍历国内(国外)的航班,设一个sum[i]表示第i个廊桥会停几架飞机,如果此时有空机位,飞机就停在空机位,sum[i]++,否则廊桥数tot++,sum[tot]=1,最后再用一个前缀和p,就可以求出当有i个廊桥的时候,可以停放多少飞机。

  这个思路的时间复杂度是O(n*(m1+m2)),完全可以过掉前40%的点了。但是我的目标是正解,我们发现,在找空机位的时候特别浪费时间,是O(n)的复杂度,我们应该去考虑一种log级别的方法。

  我先考虑的就是优先队列q1(太香了),把廊桥的编号和飞机起飞时间压入队列,按起飞时间由小到大排序,如果队首元素起飞时间大于当前遍历到的飞机,那么直接新建廊桥,否则将其停在队首廊桥上,压入队列。

 注意!这里我犯了个非常致命的错误!!!

  如果只是判定是否需要新建廊桥,是没有问题的,但是如果直接停在队首廊桥就会出现一个错误——可能会有编号更小的廊桥可以停,这样就会导致:假设这个飞机是可以停在1号廊桥,但由于3号廊桥的飞机起飞更早,导致该飞机停在了3号廊桥(所以会有啥后果呢?),那么我们在存储sum[i]的时候,就会把该飞机编入3号廊桥,也就是说至少要给国内分配3个廊桥时该飞机才可以停,那这显然不行。

正解

  于是,我又增加了一个优先队列q2,用来从小到大存当前空机位廊桥的编号,如果有飞机的降落时间大于q1队首的起飞时间,那么我们直接把队首元素弹出,并把所对的廊桥编号压入q2,然后取q2队首编号的廊桥作为当前飞机的停机点。如果飞机的降落时间小于q1队首的起飞时间,先看看q2是否有空机位,如果没有再创建一个廊桥。时间复杂度是O((m1+m2)logn),可以过。

代码

  考试时写的代码,难看繁琐,勿喷

#include <bits/stdc++.h>
using namespace std;
int n,m1,m2;

struct qu{
	int l;
	int r;
};
qu s1[101000],s2[101000];

struct node{
	int id;
	int ti;
	bool operator < (const node &x) const{
		return ti>x.ti;
	}
};

priority_queue<node> q;
priority_queue<int,vector<int>,greater<int> > q2; 
int sum1[101000],sum2[101000],p1[101000],p2[101000];
int tot1,tot2;

bool cmp(qu x,qu y){
	return x.l<y.l;
}
int main (){
	cin >> n >> m1 >> m2;
	for(int i=1;i<=m1;i++)
		cin >> s1[i].l >> s1[i].r;
	for(int i=1;i<=m2;i++)
		cin >> s2[i].l >> s2[i].r;
		
	sort(s1+1,s1+m1+1,cmp);//先按降落时间从小到大排序 
	sort(s2+1,s2+m2+1,cmp);
	
	for(int i=1;i<=m1;i++){
		if(q.empty()||q.top().ti>s1[i].l){//如果当前所用着的廊桥已经没有可以停下的了 
			if(!q2.empty()) {//如果有空机位先停空机位 
				sum1[q2.top()]++;
				q.push({q2.top(),s1[i].r});
				q2.pop();
				continue;
			}
			sum1[++tot1]++;//否则新建廊桥 
			q.push({tot1,s1[i].r});
		}else{
			while(!q.empty()&&q.top().ti<=s1[i].l){//先把所有符合要求的廊桥出队 
				node u=q.top();
				q2.push(u.id);//压入q2 
				q.pop();
			}
			sum1[q2.top()]++;//sum存储 
			q.push({q2.top(),s1[i].r});
			q2.pop();
		}
	}
	
	while(!q.empty()) q.pop();//清空q1 q2 
	while(!q2.empty()) q2.pop();
	
	for(int i=1;i<=n;i++) p1[i]=p1[i-1]+sum1[i];//前缀和求p,表示i个廊桥可停几个飞机 
	
	for(int i=1;i<=m2;i++){//国外同理 
		if(q.empty()||q.top().ti>s2[i].l){
			if(!q2.empty()) {
				sum2[q2.top()]++;
				q.push({q2.top(),s2[i].r});
				q2.pop();
				continue;
			}
			sum2[++tot2]++;
			q.push({tot2,s2[i].r});
		}else{
			while(!q.empty()&&q.top().ti<=s2[i].l){
				node u=q.top();
				q2.push(u.id);
				q.pop();
			}
			sum2[q2.top()]++;
			q.push({q2.top(),s2[i].r});
			q2.pop();
		}
	}
	
	for(int i=1;i<=n;i++) p2[i]=p2[i-1]+sum2[i];
	
	int ans=0;
	for(int i=0;i<=n;i++){//枚举廊桥的分配个数 
		ans=max(ans,p1[i]+p2[n-i]); //取最大值 
	}
	cout << ans;
	
	return 0;
}

总结

  总体来说第一题还是有一定的思维的,这是本蒟蒻第一次写题解,若有什么问题请指出

下课!

标签:飞机,q2,int,m1,2021,m2,廊桥,CSP
From: https://www.cnblogs.com/free-fish/p/18446583

相关文章

  • 安装Kali2021.1步骤(VMware16.1.2)
    脑子空空关注IP属地:上海2022.06.0417:47:41字数159阅读991 1、VMware虚拟机的下载安装都在官网,这里用的是16.1.2的版本2、Kali下载(选择VirtualMachines)  3、点击VMware64下方的下载图标(文件大小只有2G,网速快的话10-15分钟就下载完了)  4......
  • [DMY]2024 CSP-S 模拟赛 Day 7
    题目T1T2T3T4当前分数这场打成一坨了。几乎写的全是暴力。赛时开T1,不太会正解,先写了个暴力丢到那儿。胡了一个\(\mathcal{O}(n^2)\)的做法,但是样例假了,照着手推一遍发现错的很彻底。已经过了1h,于是去看T2。T2还是先写出来了暴力思路。感觉这东西......
  • 冲刺CSP联训模拟2
    冲刺CSP联训模拟2\(T1\)P294.挤压\(40pts\)部分分\(20\%\):爆搜,时间复杂度为\(O(2^{n})\)。另外\(20\%\):观察到值域较小,将值域计入状态设计,时间复杂度为\(O(nV)\)。点击查看代码constllmod=1000000007;lla[100010],p[100010],pp[100010],q[100010],f[2]......
  • 10.4 代码源 2024 CSP-S 模拟赛 Day 9
    省流:\(100+0+0+0=100\)简称:唐诗T1先写了个暴力,然后在想怎么优化,然后想了个区间DP但是写的时候又不会了……然后发现如果这一块数的二进制每一位都有一个数的这一位为\(0\)或者都相同,那么这些数合并起来一定最优,然后双指针搞,复杂度\(O(30n)\)。(这么绕口)赛后听别人说有......
  • [DMY]2024 CSP-S 模拟赛 Day 9
    T2调了1h没调出来,丢了一坨没分的shi扔了。我想放一下作为开头:include<bits/stdc++.h>#defineintlonglongusingnamespacestd;inlineintread(){intw=1,s=0;charch=getchar();while(!isdigit(ch)){if(ch'-')w=-1;ch=getchar();}while(isdigit(ch)){s=s10+(ch-......
  • 【训练记录】2024年莆田市高中信息学奥赛国庆集训CSP-S提高组(第四天场外)
    训练情况rk#1\(100+100+100+100=400\)赛后反思因为满分AK了,就不需要反思了A题显然我们想要选的最多,我们优先选\(a_i\)小的,所以我们对\(a_i\)从小到大排序,再求一个前缀和,再使用二分即可#include<bits/stdc++.h>#defineintlonglongusingnamespaces......
  • CSP-J/S2024总结
    CSP-J/S2024游记初赛前记今年最后一年J了...希望圆我个2年都没有实现的J一等梦还有希望S考好点期待1=day-1考完不放假,然后月考,高兴坏了day1没什么好说的,行就行,不行就AFO(假CSP-J本来就打算摆烂,所以不慌因为是最后一个考场,只有26人,赢!嗯?开局放int?完辣!组合题放那......
  • [北大集训 2021] 简单数据结构
    简单数据结构,但本蒟蒻觉得并不简单呐!容易发现这题的几个好用的性质:1.只要被第一个操作影响的都能够保持单调,容易一起维护。2.操作都是全局的!3.没被操作一影响的都可以表示为\(ki+a_i\)的形式。利用这些性质,我们考虑把没被操作一影响的项放在\(S\)集合,被操作一影响的项放......
  • P9752 [CSP-S 2023] 密码锁&&P8814 [CSP-J 2022] 解密
    GutenTag!Schön,dichzusehen!今天也是很懒惰的一天呢!所以今天三合一!题目:[CSP-S2023]密码锁题目描述小Y有一把五个拨圈的密码锁。如图所示,每个拨圈上是从$0$到$9$的数字。每个拨圈都是从$0$到$9$的循环,即$9$拨动一个位置后可以变成$0$或$8$,因为校园里......
  • CSP-J模拟赛一补题报告
    IAKIOI!!!前言考的最好的一回:240pts首先开T1,45min干掉了然后T2,45min挂了然后T3,40min又挂了然后发呆了一会把T4骗分打了,此时已过去一坤时40minT2切了,最后20min打了T3骗分又发呆了一会T1:100ptsT2:100ptsT3:30ptsT4:10pts《正文》01011010101001010010101011010100011......