• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
nannandbk
博客园    首页    新随笔    联系   管理    订阅  订阅
2.3 蓝桥杯练习3题

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;
}

posted on 2024-02-03 23:30  nannandbk  阅读(124)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3