当前位置: 首页 > article >正文

NO.51十六届蓝桥杯备战|堆算法题|第k小|除2|最小函数值|序列合并|舞蹈课(C++)

P3378 【模板】堆 - 洛谷
#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;
int n;
int heap[N];

void up(int child)
{
    int parent = child / 2;
    while (parent >= 1 && heap[child] < heap[parent])
    {
        swap(heap[child], heap[parent]);
        child = parent;
        parent = child / 2;
    }
}

void down(int parent)
{
    int child = parent * 2;
    while (child <= n)
    {
        if (child + 1 <= n && heap[child + 1] < heap[child]) child++;

        if (heap[child] >= heap[parent]) return;

        swap(heap[child], heap[parent]);
        parent = child;
        child = parent * 2;
    }
}

void push(int x)
{
    n++;
    heap[n] = x;
    up(n);
}

void pop()
{
    swap(heap[1], heap[n]);
    n--;
    down(1);
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int t; cin >> t;
    while (t--)
    {
        int op; cin >> op;
        if (op == 1)
        {
            int x; cin >> x;
            push(x);
        }
        else if (op == 2)
        {
            cout << heap[1] << endl;
        }
        else
        {
            pop();
        }
    }
    
    return 0;
}
第k小

用堆维护数据流中的第k小

  1. 创建一个大根堆
  2. 维护大根堆的大小为k即可
    堆顶元素就是第k小
#include <bits/stdc++.h>
using namespace std;

int n, m, k;
priority_queue<int> heap;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
        
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++)
    {
        int x; cin >> x;
        heap.push(x);
        if (heap.size() > k) heap.pop();
    }
    while (m--)
    {
        int op; cin >> op;
        if (op == 1)
        {
            int x; cin >> x;
            heap.push(x);
            if (heap.size() > k) heap.pop();
        }
        else if (op == 2)
        {
            if (heap.size() == k) cout << heap.top() << endl;
            else cout << -1 << endl;
        }
    }
    
    return 0;
}
除2

每次挑选出,当前数组中最大的偶数,减小一半

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
priority_queue<LL> heap;

int n, k;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n >> k;
    LL sum = 0;
    for (int i = 1; i <= n; i++)
    {
        int x; cin >> x;
        sum += x;
        if (x % 2 == 0) heap.push(x);
    }
    while (heap.size() && k--)
    {
        int t = heap.top() / 2;
        heap.pop();
        
        sum -= t;
        if (t % 2 == 0) heap.push(t);
    }
    cout << sum << endl;
    
    return 0;
}
P2085 最小函数值 - 洛谷

解法1:暴力求解
求出所有函数中的m个值,然后取前n个
解法2:利用堆+二次函数单调性
因为a和b都大于0,所以-b/2a一定小于0,对称轴在y轴左边,但是x取正整数,所以函数一定单调递增
仅需将x=1的所有函数值计算出来
然后每次拿出最小的那个,把对应的下一个函数值再计算出来
那么就可以用小根堆来实现这个过程

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 1e4 + 10;

int n, m;
LL a[N], b[N], c[N];

struct node
{
    LL f;
    LL num;
    LL x;

    bool operator < (const node& x) const
    {
        //小根堆,大元素下坠
        return f > x.f;
    }
};

priority_queue<node> heap;

LL calc(LL i, LL x)
{
    return a[i] * x * x + b[i] * x + c[i];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i] >> b[i] >> c[i];        
    }

    for (int i = 1; i <= n; i++)
    {
        heap.push({calc(i, 1), i, 1});        
    }

    while (m--)
    {
        auto t = heap.top(); heap.pop();
        LL f = t.f, num = t.num, x = t.x;

        cout << f << " ";

        heap.push({calc(num, x + 1), num, x + 1});
    }
    
    return 0;
}
P1631 序列合并 - 洛谷

解法1:暴力求解
把所有的和全部算出来,然后找出最小的n个
解法2:利用单调性
先把a[i]+b[i]的所有值计算出来,放进小根堆中
然后拿出最小的值即堆顶元素,把下一个和再计算出来,再放入堆中
堆里面要存 和,a的编号,b的编号

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;

int n;
int a[N], b[N];

struct node
{
    int sum;
    int i, j;

    bool operator < (const node& x)const
    {
        return sum > x.sum;
    }
};

priority_queue<node> heap;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) cin >> b[i];

    //将ai+b1放进堆里面
    for (int i = 1; i <= n; i++)
    {
        heap.push({a[i] + b[1], i, 1});        
    }
    //依次拿出n个数
    for (int k = 1; k <= n; k++)
    {
        node t = heap.top(); heap.pop();
        int sum = t.sum, i = t.i, j = t.j;

        cout << sum << " ";
        if (j + 1 <= n) heap.push({a[i] + b[j + 1], i, j + 1});
    }
        
    return 0;
}
P1878 舞蹈课 - 洛谷

解法:利用小根堆,存所有相邻异性的差值,每次拿出最小的即可

  1. 取出相邻的一对异性之后,他们的左右,有可能变成新的一对
    用双向链表存队列
  2. 堆中,有可能存在已经出列的人
    bool st[N]sti表示i这个人是否已经出队
  3. 堆中存什么
    技术差,左编号,右编号
#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;

int n;
int s[N]; //标记男女,0/1

int e[N];
int pre[N], ne[N];

struct node
{
    int d;
    int l, r;

    bool operator < (const node& x)const
    {
        if (d != x.d) return d > x.d;
        else if (l != x.l) return l > x.l;
        else return r > x.r;
    }
};

priority_queue<node> heap;
bool st[N]; //标记出队的人
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        char ch; cin >> ch;
        if (ch == 'B') s[i] = 1;
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> e[i];
        pre[i] = i - 1;
        ne[i] = i + 1;
    }
    pre[1] = ne[n] = 0;

    //把所有的差放进堆中
    for (int i = 2; i <= n; i++)
    {
        if (s[i] != s[i - 1])
        {
            heap.push({abs(e[i] - e[i - 1]), i - 1, i});
        }
    }

    //提取结果
    vector<node> ret; //暂存结果
    while (heap.size())
    {
        node t = heap.top(); heap.pop();
        int d = t.d, l = t.l, r = t.r;
        
        if (st[l] || st[r]) continue;

        ret.push_back(t);
        st[l] = st[r] = true; //标记l和r已经出列

        //修改指针,还原新的队列
        ne[pre[l]] = ne[r];
        pre[ne[r]] = pre[l];

        int left = pre[l], right = ne[r];
        if (left && right && s[left] != s[right])
        {
            heap.push({abs(e[left] - e[right]), left, right});
        }
    }

    cout << ret.size() << endl;
    for (auto& x : ret)
    {
        cout << x.l << " " << x.r << endl;        
    }
    
    return 0;
}

http://www.kler.cn/a/594103.html

相关文章:

  • K8S学习之基础四十:K8S配置altermanager发送告警到钉钉群
  • SpringCache @Cacheable 在同一个类中调用方法,导致缓存不生效的问题及解决办法
  • Springboot项目搭建(9)-分页与文件上传
  • 论文阅读——高光谱与多光谱图像融合:通过自监督表示实现任意分辨率
  • 用爬虫解锁 Shopee 店铺商品数据,开启电商新洞察
  • Thinkphp指纹识别
  • HarmonyOS Next~鸿蒙系统架构设计解析:分层、模块化与智慧分发的技术革新
  • POI和EasyExcel---处理Excel
  • Python散点图(Scatter Plot):数据探索的“第一张图表”
  • QQ远程控制一连接就结束怎么办?
  • 各种排序汇总
  • 在VMware上部署【Ubuntu】
  • List 和 Set 的区别
  • UI设计中的视觉引导:让用户聚焦关键信息
  • 大语言模型的长思维链推理:综述(上)
  • 【计算机视觉】工业表计读数(1)--基于关键点检测的读数识别方案
  • 系统运营中的数据治理
  • 【AI】AI编程助手:Cursor、Codeium、GitHub Copilot、Roo Cline、Tabnine
  • id: ‘dev.flutter.flutter-plugin-loader‘, version: ‘1.0.0‘怎么解决
  • lunar是一款无第三方依赖的公历 python调用