蓝桥杯C++大学B组一个月冲刺记录2024/3/12
规则:每日三题
时间过得好快…
1.挤牛奶
每天早上 5点,三名农夫去牛场给奶牛们挤奶。
现在从 5点开始按秒计时,第一名农夫在第 300秒开始给牛挤奶,并在第 100 秒停止挤奶。
第二名农夫在第 700秒开始给牛挤奶,并在第 1200秒停止挤奶。
第三名农夫在第 150 秒开始给牛挤奶,并在第 2100秒停止挤奶。
从开始挤奶到挤奶完全结束,这一期间,至少存在一名农夫正在挤奶的连续时间段的长度最长为 900秒(第 300秒至第 1200秒),完全没有任何农夫在挤奶的连续时间段的长度最长为 300秒(第 1200 秒至第 1500秒)。
现在给你 N名农夫挤 N头奶牛的工作时间表,请你求出:
至少存在一名农夫正在挤奶的连续时间段的最长长度。没有任何农夫在挤奶的连续时间段的最长长度。
区间合并:计算一下合并完区间的长度,以及下一个不在该区间的区间左端点到当前区间的右端点的长度就可以了
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int>PII;
vector<PII>q;
int ans,len;
int l,r,n;
bool cmp(PII a,PII b){
return a.first < b.first;
}
int main(){
cin >> n;
for(int i = 1;i <= n; ++i){
cin >> l >> r;
q.push_back({l,r});
}
sort(q.begin(),q.end(),cmp);
for(int i = 0;i < n;++i){
if(i == 0){
l = q[i].first,r = q[i].second;
ans = r - l;
}
else{
if(q[i].first <= r){
r = max(q[i].second , r);
ans = max(ans , r - l);
}
else{
len = max(q[i].first - r , len);
l = q[i].first,r = q[i].second;
ans = max(ans , r - l);
}
}
}
cout << ans << ' ' << len << endl;
return 0;
}
2.区间合并
给定 n个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如:[1,3]和 [2,6]可以合并为一个区间 [1,6]。
区间合并: 模板题,注意相交区间的定义是在端点处相交还是相邻
(另外:个人认为非抽象的区间合并可以使用差分数组来记录状态的做。因为常规区间合并的做法包含了sort时间复杂度O(nlogn) , 差分数组的做法能够降到O(n))
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int>PII;
vector<PII>q;
int n,ans = 0;
bool cmp(PII a,PII b){
return a.first < b.first;
}
int main(){
cin >> n;
for(int i = 0;i < n;++i){
PII t;
cin >> t.first >> t.second;
q.push_back(t);
}
sort(q.begin(),q.end(),cmp);
int l = 0,r = 0;
for(int i = 0;i < n;++i){
if(i == 0) l = q[i].first, r = q[i].second,ans = 1;
else{
if(q[i].first <= r) r = max(q[i].second , r);
else{
ans ++;
l = q[i].first,r = q[i].second;
}
}
}
cout << ans << endl;
return 0;
}
3.校门外的树
某校大门外长度为 L的马路上有一排树,每两棵相邻的树之间的间隔都是 1米。
我们可以把马路看成一个数轴,马路的一端在数轴 0的位置,另一端在 L的位置;数轴上的每个整数点,即 0,1,2,……,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。
这些区域用它们在数轴上的起始点和终止点表示。
已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。
现在要把这些区域中的树(包括区域端点处的两棵树)移走。
你的任务是计算将这些树都移走后,马路上还有多少棵树。
区间合并: 每次记录一下区间合并完的长度即可
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int,int>PII;
vector<PII>q;
int len,ans = 0;
int n,l,r;
int L;
bool cmp(PII a,PII b){
return a.first < b.first;
}
int main(){
cin >> L >> n;
for(int i = 1;i<=n;++i){
cin >> l >> r;
q.push_back({l,r});
}
sort(q.begin(),q.end(),cmp);
for(int i = 0;i < n; ++i){
if(i == 0){
l = q[i].first,r = q[i].second,len = r - l;
}
else{
if(q[i].first <= r){
r = max(q[i].second,r);
len = max(r - l , len);
}
else{
ans += len + 1;
l = q[i].first,r = q[i].second;
len = r - l;
}
}
}
ans += len + 1;
cout << L - ans + 1 << endl;
return 0;
}
4.管道
有一根长度为 len 的横向的管道,该管道按照单位长度分为 len段,每一段的中央有一个可开关的阀门和一个检测水流的传感器。
一开始管道是空的,位于 Li的阀门会在 Si时刻打开,并不断让水流入管道。
对于位于 Li的阀门,它流入的水在 Ti(Ti≥Si)时刻会使得从第 Li−(Ti−Si)段到第 Li+(Ti−Si) 段的传感器检测到水流。
求管道中每一段中间的传感器都检测到有水流的最早时间。
区间合并+二分: 这个题关键是想到答案具有二分关系,check函数使用区间合并来判断。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int>PII;
typedef long long LL;
vector<PII>q;
int n,len;
LL l,r;
bool cmp(PII a, PII b){
return a.first < b.first;
}
bool check(int k){
vector<PII>temp;
for(int i = 0;i < n;++i){
if(q[i].second <= k){
int ll = max(1,q[i].first - (k - q[i].second));
int rr = min((LL)len,(LL)q[i].first + (k - q[i].second));
temp.push_back({ll,rr});
}
}
sort(temp.begin(),temp.end(),cmp);
int l = 0,r = 0;
for(int i = 0;i < temp.size();++i){
if(i == 0) l = temp[i].first,r = temp[i].second;
else{
if(temp[i].first <= r + 1) r = max(r,temp[i].second);
else l = temp[i].first,r = temp[i].second;
}
}
return l == 1&&r == len;
}
int main(){
cin >> n >> len;
for(int i = 1;i <= n;++i){
cin >> l >> r;
q.push_back({l,r});
}
l = 0,r = 2e9;
while(l < r){
int mid = (LL)(l + r)/2;
if(check(mid) == false) l = mid + 1;
else r = mid;
}
cout << l << endl;
return 0;
}