与堆有关问题的求解

洛谷

P2085 最小函数值

https://www.luogu.org/problemnew/show/P2085

题目大意:有n个函数,分别为 F 1 , F 2 , . . . , F n F_1,F_2,...,F_n F1,F2,...,Fn。定义Fi(x)= A i A_i Ai* x 2 x^2 x2+ B i B_i Bix+ C i C_i Ci (x∈N)。给定这些 A i 、 B i 和 C i A_i、B_i和C_i AiBiCi,请求出所有函数的所有函数值中最小的m个(如有重复的要输出多个)。

由于n,m很大,这里就不能全部举例然后排序了,会超时,也会爆内存。
所以这里就用到了堆的思想了。维护堆里的最小值,在往里面放然后继续维护。
思路是这样的: 首先,我们可以在所有“箭头”指向1的时候,对所有箭头对应的函数值建立小根堆;然后,每次从堆顶取走那个数,并将其所对应的“箭头”指向下一个函数值,然后把这个新的函数值代替那个取走的函数值放在堆顶,并自顶向下维护堆(大家可以证明一下,一直这样操作下去,堆的性质恒成立)。

代码很简洁,可以套用这类的问题:

#include<bits/stdc++.h>
#include<queue>
using namespace std;
int a[100005],b[100005],c[100005],to[100005],i,n,m;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;//先按first排,再按second排
int main()
{
    scanf("%d %d",&n,&m);
    for (i=1;i<=n;i++){
        to[i]=1;
        scanf("%d %d %d",&a[i],&b[i],&c[i]);
        q.push(pair<int,int>(a[i]+b[i]+c[i],i));
    }
    while (m--){
        printf("%d ",q.top().first);
        i=q.top().second;q.pop();
        q.push(pair<int,int>(a[i]*(++to[i])*(to[i])+b[i]*to[i]+c[i],i));
    }
    return 0;
}

同类题:

P1631 序列合并

https://www.luogu.org/problemnew/show/P1631

有两个长度都是N的序列A和B,在A和B中各取一个数相加可以得到 N 2 N^2 N2个和,求这 N 2 N^2 N2个和中最小的N个。

先让 a 1 a_1 a1与所有的 b i b_i bi相加,然后每出栈一个则将 b i 与 下 一 个 a i b_i与下一个a_i biai相加,放入优先队列中。

#include<bits/stdc++.h>
#include<queue>
using namespace std;
int a[100005], b[100005], to[100005],i, n;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;//先按first排,再按second排
int main()
{
    scanf("%d",&n);
    for (i=1;i<=n;i++)
        scanf("%d", &a[i]);
    for (i=1;i<=n;i++){
        scanf("%d",&b[i]);to[i]=1;
        q.push(pair<int,int>(a[1]+b[i],i));
    }
    while (n--){
        printf("%d ",q.top().first);
        i = q.top().second; q.pop();
        q.push(pair<int,int>(a[++to[i]]+b[i],i));
    }
    return 0;
}

P1801 黑匣子_NOI导刊2010提高(06)

https://www.luogu.org/problemnew/show/P1801
最基本的堆问题。

在这里插入图片描述
题目大意:
add往队列里加数,每次get则i++,输出第i大的数。
这只需两个堆,一个大顶堆,一个小顶堆,大顶堆,维持i数量个容积即可。然后放入大顶堆中,大于i的放入小顶堆中,每次比较大顶堆与小顶堆的大小。

#include <cstdio>
#include <queue>
#include <iostream>

using namespace std;

int main(){
    int a[200001];
    priority_queue<int>A;//单调递减,大顶堆
    priority_queue<int,vector<int>,greater<int>>B; //单调递增,小顶堆
    int n,m,r=1,q;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=m;i++){
        cin>>q;
        for(int j=r;j<=q;j++){
            A.push(a[j]);
            if(A.size()==i) B.push(A.top()),A.pop(); //超过大小,移除元素
        }
        r=q+1;
        printf("%d\n",B.top()); //输出每次 GET 的答案
        A.push(B.top()),B.pop(); //为下一次的 GET 作准备,填满小顶堆的空间
    }
    return 0;
}

P1484 种树

https://www.luogu.org/problemnew/show/P1484

cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。

题目很容易想到DP
f[ i ][ j ]表示种到第i棵树且种了j棵的最大获利,则f[ i ][ j ]=max(f[ i-1 ][ j ],f[ i-2 ][ j-1 ]+a[ i ])
但很明显n太大了不成立。

所以这里的做法是:
设k为放入的个数,先找到最大值放入堆中,每次找到最大的如果k=1时最优解为a[i],那么我们便可以把a[i-1]和a[i+1]进行合并,因为它们要么同时被选,要么同时落选(证明不难,请自行解决)。而且,我们还注意到:当选了a[i-1]和a[i+1]时,获利便增加了a[i-1]+a[i+1]-a[i]。所以当a[i]被选时,我们就可以删去a[i-1]和a[i+1],并把a[i]改成a[i-1]+a[i+1]-a[i],重新找最大的。

凭感觉会觉得不成立,但是推一下,是成立的。

每次找的都是最大的数,我们便可以使用堆进行操作,直到堆中最大值小于0或取出k个数后停止。复杂度O(klogn)。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e5+5;
struct cs{
    ll v;int id;
    bool operator<(const cs &a)const {return v<a.v;}
}t;
priority_queue<cs>Q;
ll a[N],ans;
int l[N],r[N];
bool ok[N];
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&t.v);
        a[i]=t.v;
        t.id=i;
        l[i]=i-1;
        r[i]=i+1;
        Q.push(t);
    }
    r[0]=1;l[n+1]=n;
    while(m--){
        while(ok[Q.top().id])Q.pop();
        t=Q.top();Q.pop();
        if(t.v<0)break;
        ans+=t.v;
        int x=t.id;
        a[x]=a[l[x]]+a[r[x]]-a[x];
        t.v=a[x];
        ok[l[x]]=ok[r[x]]=1;
        l[x]=l[l[x]];r[l[x]]=x;
        r[x]=r[r[x]];l[r[x]]=x;
        Q.push(t);
    }
    printf("%lld",ans);
}

做洛谷堆的题目主要是为了做后面的树状数组和线段树的题目,顺便给堆也做做笔记hhh。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
1. 智慧监狱概述 智慧监狱的建设背景基于监狱信息化的发展历程,从最初的数字化监狱到信息化监狱,最终发展到智慧监狱。智慧监狱强调管理的精细化、监管的一体化、改造的科学化以及办公的无纸化。政策上,自2017年以来,司法部连续发布了多项指导性文件,推动智慧监狱的建设。 2. 内在需求与挑战 智慧监狱的内在需求包括数据应用与共享的不足、安防系统的单一功能、IT架构的复杂性、信息安全建设的薄弱以及IT运维的人工依赖。这些挑战要求监狱系统进行改革,以实现数据的深度利用和业务的智能化。 3. 技术架构与设计 智慧监狱的技术架构包括统一门户、信息安全、综合运维、安防集成平台和大数据平台。设计上,智慧监狱采用云计算、物联网、大数据和人工智能等技术,实现资源的动态分配、业务的快速部署和安全的主动防护。 4. 数据治理与应用 监狱数据应用现状面临数据分散和共享不足的问题。智慧监狱通过构建数据共享交换体系、数据治理工具及服务,以及基于数据仓库的数据分析模型,提升了数据的利用效率和决策支持能力。 5. 安全与运维 智慧监狱的信息安全建设涵盖了大数据应用、安全管理区、业务区等多个层面,确保了数据的安全和系统的稳定运行。同时,综合运维平台的建立,实现了IT系统的统一管理和自动化运维,提高了运维效率和系统的可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值