2.3 蓝桥杯练习3题
1.[P9241 蓝桥杯 2023 省 B] 飞机降落
题意:\(N\) 架飞机准备降落到某个只有一条跑道的机场。其中第 \(i\) 架飞机在 \(T_{i}\) 时刻到达机场上空,到达时它的剩余油料还可以继续盘旋 \(D_{i}\) 个单位时间,即它最早可以于 \(T_{i}\) 时刻开始降落,最晩可以于 \(T_{i}+D_{i}\) 时刻开始降落。降落过程需要 \(L_{i}\) 个单位时间。
一架飞机降落完毕时,另一架飞机可以立即在同一时刻开始降落,但是不能在前一架飞机完成降落前开始降落。
请你判断 \(N\) 架飞机是否可以全部安全降落。
思路:一开始我是想贪心,但发现搞不了啊。一开始应该看数据范围啊啊啊,只有10,这不直接爆搜?藕直接全排列(用\(b[i]\)数组记录了)然后判断了。
注意判断的写法:\(now\)为上一个飞机降落时刻。我们肯定让第一个飞机最早时刻降落,那么\(now\)初始化为\(a[b[1]].t+a[b[1]].l\)。然后从第二个开始check,用\(s\)记录当前飞机降落时刻,那么令\(s = a[b[i]].t\)。先判断当前飞机能否安全降落,\(s + a[b[i]].d\ge now\)就可以,否则就不行。如果能安全降落,考虑去更新\(now\),如果\(s < now\)则令\(s = now\),\(now = s + a[b[i]].l\)。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
struct node
{
int t,d,l;
}a[N];
int n;
int b[N];
bool flag = false;
bool vis[N];
void dfs(int step)
{
if(flag)return;
if(step>n)
{
int now = a[b[1]].t + a[b[1]].l;
bool ok = true;
for(int i = 2;i <= n; i++)
{
if(a[b[i]].t + a[b[i]].d >= now)
{
int s = a[b[i]].t;
if(s < now)s = now;
now = s + a[b[i]].l;
}
else{
ok = false;
break;
}
}
if(ok)flag = true;
}
for(int i = 1;i <= n; i++)
{
if(!vis[i])
{
vis[i] = true;
b[step] = i;
dfs(step+1);
vis[i] = false;
}
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int tc; cin>>tc;
while(tc--)
{
cin>>n;
memset(vis,false,sizeof(vis));
flag = false;
for(int i = 1;i <= n; i++)
cin>>a[i].t>>a[i].d>>a[i].l;
dfs(1);
if(flag)cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
2.[P8661 蓝桥杯 2018 省 B] 日志统计
题意:小明维护着一个程序员论坛。现在他收集了一份“点赞”日志,日志共有 \(N\) 行。其中每一行的格式是 ts id
,表示在 \(ts\) 时刻编号 \(id\) 的帖子收到一个“赞”。
现在小明想统计有哪些帖子曾经是“热帖”。如果一个帖子曾在任意一个长度为 \(D\) 的时间段内收到不少于 \(K\) 个赞,小明就认为这个帖子曾是“热帖”。
具体来说,如果存在某个时刻 \(T\) 满足该帖在 \([T,T+D)\) 这段时间内(注意是左闭右开区间)收到不少于 \(K\) 个赞,该帖就曾是“热帖”。
给定日志,请你帮助小明统计出所有曾是“热帖”的帖子编号。
思路:单调队列维护,有点滑动窗口的味道。如果\(当前的时刻-对头的时间>d\)则把对头的出队,如果队列里面的元素个数\(\ge D\),则是热帖。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
deque<int>q[N];
int n,d,k;
struct node
{
int ts,id;
}a[N];
bool cmp(node a,node b)
{
return a.ts<b.ts;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
cin>>n>>d>>k;
for(int i = 1;i <= n; i++)
cin>>a[i].ts>>a[i].id;
sort(a+1,a+1+n,cmp);
set<int>s;
for(int i = 1;i <= n; i++)
{
int ts = a[i].ts;
int id = a[i].id;
while(!q[id].empty() && ts-*q[id].begin() >= d)q[id].pop_front();
q[id].push_back(ts);
if(q[id].size()>=k)s.insert(id);
}
for(auto x : s)
cout<<x<<"\n";
return 0;
}
3.[P9240 蓝桥杯 2023 省 B] 冶炼金属
题意:小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 \(V\),\(V\) 是一个正整数,这意味着消耗 \(V\) 个普通金属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 \(V\) 时,无法继续冶炼。
现在给出了 \(N\) 条冶炼记录,每条记录中包含两个整数 \(A\) 和 \(B\),这表示本次投入了 \(A\) 个普通金属 O,最终冶炼出了 \(B\) 个特殊金属 X。每条记录都是独立的,这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。
根据这 \(N\) 条冶炼记录,请你推测出转换率 \(V\) 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况。
思路:不知道为啥,藕一眼二分,直接写。下面是我写的答辩。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int a[N],b[N];
int n;
int judge(int x)
{
for(int i = 1;i <= n; i++)
{
if(a[i]/x < b[i])return 1;
else if(a[i]/x > b[i])return 2;
}
return 0;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
cin>>n;
for(int i = 1;i <= n; i++)
cin>>a[i]>>b[i];
int l = 0, r = 1e9;
int mx = 0,mn = 1e9;
while(l <= r)
{
int mid = (l+r)>>1;
int res = judge(mid);
if(res == 1)r = mid-1;
else if(res == 2)l = mid+1;
else{
r = mid-1;
}
}
mn = r + 1;
l = 0, r = 1e9;
while(l <= r)
{
int mid = (l+r)>>1;
int res = judge(mid);
if(res == 1)r = mid-1;
else if(res == 2)l = mid+1;
else{
l = mid+1;
}
}
mx = l - 1;
cout<<mn<<" "<<mx<<"\n";
return 0;
}
虽然是过了哈,看到题解里面大佬两行就写好了。fine,还是自己太菜了,学习了一下。
mx的答案用每组数据最大值的最小值,mn的答案用所有数据最小值的最大值。因为这样才能满足所有的条件。
最大\(\lfloor\dfrac{a}{b}\rfloor\),最小\(\lfloor\dfrac{a}{b+1}\rfloor+1\)(因为\(\lfloor\dfrac{a}{b+1}\rfloor\)作为刚好不满足条件的情况)
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int n,a[N],b[N];
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
cin>>n;
for(int i = 1;i <= n; i++)
cin>>a[i]>>b[i];
int mx = 1e9,mn = 0;
for(int i = 1;i <= n; i++)
{
mx = min(mx,a[i]/b[i]);
mn = max(mn,a[i]/(b[i]+1)+1);
}
cout<<mn<<" "<<mx<<"\n";
return 0;
}