题目传送门

贪心:

一个人 \(i\) 要投票,两种情况:花钱,或当前的人数达到了 \(m_i\)。

而当前达到 \(m_i\) 的话所有 \(m_j \le m_i\) 也就达到要求了。

所以考虑将所有人按 \(m\) 从小到大排序。用 \(vetcor\) 当桶。

其次考虑如何贿赂最优。当前如果要达到 \(m_i\),优先考虑贿赂 \(m\) 更大的。因为贿赂比他小的可以达到的还是 \(m_i\),贿赂比他大的就可以达到 \(m_i+1\)。同时,后面的要求比前面高,不用再考虑,会更优。

而在比 \(m_i\) 大的所有人中,贪心贿赂 \(p_i\) 更小的显然更好。所以,需要维护比 \(m_i\) 大的所有人中 \(p_i\) 的最小值。考虑用小根堆维护。

堆:

没怎么用过,补

用 \(stl\) 中的优先队列。

小根堆:

priority_queue< 数据类型 ,vector< 数据类型 >,greater< 数据类型 > > q;

大根堆:

priority_queue< 数据类型 > q;

priority_queue< 数据类型 ,vector< 数据类型 >,less< 数据类型 > > q;

基本操作:

empty()  //判断一个队列是否为空
pop() //删除队顶元素
push(x) //加入一个元素 x
size() //返回优先队列中拥有的元素个数
top() //返回优先队列的队顶元素

其存取时间复杂度 \(O(logn)\)

板:

P3378

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,op;
ll x;
priority_queue<ll,vector<ll>,greater<ll> > q;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&op);
if(op==1){
scanf("%lld",&x);
q.push(x);
}
else if(op==2) printf("%lld\n",q.top());
else q.pop();
}
return 0;
}

P1334 瑞瑞的木板

将分割看成合成。每次选取两块长度最小的合答案最小。

用小根堆维护当前最小两块板,合完删掉这两块,并加入他们的和。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,a,_1,_2;
ll ans;
priority_queue<int,vector<int>,greater<int> > q;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a);
q.push(a);
}
for(int i=1;i<n;i++){
_1=q.top(),q.pop();
_2=q.top(),q.pop();
q.push(_1+_2);
ans+=(ll)_1+(ll)_2;
}
printf("%lld",ans);
return 0;
}

双倍经验:合并果子

对顶堆:

对顶堆用于维护第 \(k\) 大的数。

是堆顶相对的一个大根堆和一个小根堆,其中小根堆存较大的一部分数,大根堆存较小的一部分数。大根堆堆顶一般是第 \(k\) 大数。插入:根据需要插到插到大根堆或小根堆,然后调整堆顶。

P1801 黑匣子

用对顶对维护第 \(i\) 大的数。插入到大根堆,若还不到 \(get\) 就把大根堆堆顶调到小根堆。每次 \(get\) 后调整一位堆顶,达到 \(i++\) 的效果。

#include<bits/stdc++.h>
using namespace std;
int n,m,a[200005],u[200005],now;
priority_queue<int> b;
priority_queue<int,vector<int>,greater<int> > s;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d",&u[i]);
for(int i=1;i<=m;i++){
while(now<u[i]){
b.push(a[++now]);
s.push(b.top());
b.pop();
}
printf("%d\n",s.top());
b.push(s.top());
s.pop();
}
return 0;
}

P1168 中位数

若当前数 \(>mid\),则放到小根堆,否则放到大根堆。

每次奇数个都要查询并更新 \(mid\),所以两个堆的大小差不超过 \(2\)。所以每次奇数个时,判断。若小根堆更大就更新 \(mid\) 为小根堆堆顶,并向大根堆调整。若大根堆更大,就更新 \(mid\) 为大根堆堆顶,并向小根堆调整。若大小相等, \(mid\) 不变。

#include<bits/stdc++.h>
using namespace std;
int n,a,mid;
priority_queue<int> b;
priority_queue<int,vector<int>,greater<int> > s;
int main(){
scanf("%d%d",&n,&a);
printf("%d\n",a);
mid=a;
for(int i=2;i<=n;i++){
scanf("%d",&a);
if(a>mid) s.push(a);
else b.push(a);
if(i%2==0) continue;
if(b.size()>s.size()){
s.push(mid);
mid=b.top();
b.pop();
}
else if(b.size()<s.size()){
b.push(mid);
mid=s.top();
s.pop();
}
printf("%d\n",mid);
}
return 0;
}

重载运算符

用于结构体中的比较。

P1878 舞蹈课

删除后补位,用链表实现。

同时,优先取插值较小的一对,可以用小根堆维护每一对的差值。同时要记录两人的编号,要用结构体。

首先把初始的相邻男女插到堆中,之后每次取堆顶记录答案,取完后标记掉,并更新左右编号(链表)。若出现的新的可行的一对,就再入队,直到队列为空。

重载运算符中,第一关键字为差值,第二关键字为左边人的编号。

#include<bits/stdc++.h>
using namespace std;
int n,a[200005],cnt=0,ans[2][200005];
int l[200005],r[200005],x,y;
bool fl=1,mark[200005];
struct node{
int w,c,d;
};
bool operator<(node a,node b){
if(a.w!=b.w) return a.w>b.w;
else return a.c>b.c;
}
priority_queue<node> q;
string s;
int main(){
scanf("%d",&n);
cin>>s;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++){
if(s[i-1]!=s[i]){
node k;
k.w=abs(a[i]-a[i+1]),k.c=i,k.d=i+1;
q.push(k);
}
}
for(int i=1;i<=n;i++) l[i]=i+1,r[i]=i-1;
while(q.size()){
node t=q.top();
q.pop();
x=t.c,y=t.d;
if(mark[x]!=0||mark[y]!=0) continue;
l[r[x]]=l[y];
r[l[y]]=r[x];
ans[0][++cnt]=x,ans[1][cnt]=y;
mark[x]=mark[y]=1;
if(mark[r[x]]==0&&mark[l[y]]==0){
if((s[r[x]-1]+s[l[y]-1])==('G'+'B')){
node k;
k.w=abs(a[r[x]]-a[l[y]]),k.c=r[x],k.d=l[y];
q.push(k);
}
}
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++) printf("%d %d\n",ans[0][i],ans[1][i]);
return 0;
}

P1631 序列合并

因为两数列按顺序给出,所以可以得到:

不管怎么样,\(A\) 序列中的第一个数绝对要选,那么这个数可能和 \(B\) 序列中的任何一个数组成的数对被选,全部加入优先队列中,这样处理了 \(i,j+1\) 的情况。

还有 \(i+1,j\) 的情况,每次输出一个和之后,将 \(B\) 序列中的第 \(i\) 个数对应的 \(A\) 序列中的第 \(j\) 个数的 \(j++\),组成数对。

但是这样数对还是容易重复。可以用一个数组记录一下,\(id[i]\) 表示 \(B\) 序列中的第 \(i\) 个数与 \(A\) 序列中的第几个数相加,每次入队的时候累加 \(id\) 数组就不会造成重复了。

用结构体存和与序号。但 priority_queue<node> 是大根堆,而本题需要小根堆。所以重载运算符:

bool operator<(node a,node b){
return a.v>b.v;
}

将小于强制定义为大于即可。

#include<bits/stdc++.h>
using namespace std;
struct node{
int v,c;
};
bool operator<(node a,node b){
return a.v>b.v;
}
priority_queue<node> q;
node k;
int a[100005],b[100005],id[100005],n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
id[i]=1;
k.v=a[1]+b[i],k.c=i;
q.push(k);
}
for(int i=1;i<=n;i++){
printf("%d ",q.top().v);
int tmp=q.top().c;
q.pop();
k.v=a[++id[tmp]]+b[tmp],k.c=tmp;
q.push(k);
}
return 0;
}

解决:

首先按 \(m\) 的大小,分别放在 \(vector\) 中。

然后 \(i\) 从 \(n-1\) 开始(从大到小),每次先把 \(m\) 值为 \(i\) 的人的贿赂花费放到小根堆中,然后比较堆的大小和 \(n-i\)。若 \(q.size()>n-i\) ,则说明人数不够,就挑堆顶贿赂,直到够了为止。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T,n,p,m,ans;
vector<ll> a[200005];
priority_queue<ll,vector<ll>,greater<ll> > q;
void cl(){
ans=0;
for(int i=0;i<=n;i++) a[i].clear();
while(q.size()) q.pop();
}
void solve(){
scanf("%lld",&n);
cl();
for(int i=1;i<=n;i++){
scanf("%lld%lld",&m,&p);
a[m].push_back(p);
}
for(int i=n-1;i>=0;i--){
for(int j=0;j<a[i].size();j++){
q.push(a[i][j]);
}
while(q.size()>n-i){
ans+=q.top();
q.pop();
}
}
printf("%lld\n",ans);
return ;
}
int main(){
scanf("%lld",&T);
while(T--) solve();
return 0;
}

【笔记】CF1251E Voting 及相关的更多相关文章

  1. amazeui学习笔记--css(布局相关1)--网格Grid

    amazeui学习笔记--css(布局相关1)--网格Grid 一.总结 基本使用 1.div+class布局:amaze里面采取的就是div+class的布局方式  <div class=&q ...

  2. amazeui学习笔记--css(布局相关3)--辅助类Utility

    amazeui学习笔记--css(布局相关3)--辅助类Utility 一.总结 1.元素清除浮动: 添加 am-cf 这个 class 即可 2.水平滚动: .am-scrollable-horiz ...

  3. amazeui学习笔记--css(布局相关2)--等分网格 AVG Grid

    amazeui学习笔记--css(布局相关2)--等分网格 AVG Grid 一.总结 1.与grid区别:网格中:am-g + am-u-xx-n 等分网格中只有一个: am-avg-sm-4(在u ...

  4. 11G RAC 中 OCR 及Voting Disk 相关操作

    一.启动oracle clusterware先决条件:Oracle High Availability Services daemon(OHASD)运行在所有集群节点上1.启动整个Oracle Clu ...

  5. shell 脚本实战笔记(7)--集群网络相关知识和环境搭建

    前言: 对网络相关的知识, 做下笔记. 包括IP地址A/B/C的分类, 静态地址的配置/DNS配置, 以及网卡相关信息查看. *) A/B/C/D类网络地址的划分 IP地址=网络地址+主机地址 或 I ...

  6. ElasticSearch学习笔记-02集群相关操作_cat参数

    _cat参数允许你查看集群的一些相关信息,如集群是否健康,有哪些节点,以及索引的情况等的. 检测集群是否健康 curl localhost:9200/_cat/health?v 说明: curl 是一 ...

  7. [开发笔记]-Windows Service服务相关注意事项

    注意一:报错:“本地计算机上的 *** 服务启动后停止.某些服务在未由其他服务或程序使用时将自动停止.” 该问题主要的原因是 Service服务程序中有错误. 遇到这个问题时,无论是重新安装服务,还是 ...

  8. CentOS学习笔记--基本命令--目录的相关操作

    Linux基本命令--目录的相关操作 常见的处理目录的命令吧: cd:变换目录 pwd:显示目前的目录 mkdir:创建一个新的目录 rmdir:删除一个空的目录 cd (变换目录) cd是Chang ...

  9. LoRaWAN_stack移植笔记(一)--RF硬件相关

    和硬件相关的问题 TCXO 的使用 根据SX1276数据手册, 如果使用TCXO,则需要配置RegTcxo寄存器为0x19,代码如下 ``` c void SX1276SetTcxoConfig(vo ...

随机推荐

  1. 实时降噪(Real-time Denoising):Spatio-Temporal Filtering

    目录 空间滤波(Spatial Filtering) 基于距离的高斯滤波 双边滤波(Bilateral filtering) 联合双边滤波(Joint Bilateral filtering)[201 ...

  2. 大家都能看得懂的源码 - 那些关于DOM的常见Hook封装(一)

    本文是深入浅出 ahooks 源码系列文章的第十四篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 上一篇我们探讨了 ahooks 对 DOM 类 Hooks 使用 ...

  3. ipad好伴侣

    https://museapp.com/ Muse是用于研究笔记,阅读,草图,屏幕截图和书签的空间画布.

  4. Java内部类初探

    Java内部类初探 之前对内部类的概念不太清晰,在此对内部类与外部类之间的关系以及它们之间的调用方式进行一个总结. Java内部类一般可以分为以下三种: 成员内部类 静态内部类 匿名内部类 一.成员内 ...

  5. Elasticsearch:理解 mapping 中的 null_value

    转载自:https://elasticstack.blog.csdn.net/article/details/114266732 null 不能被索引或搜索. 当字段设置为 null(或空数组或 所有 ...

  6. MongoDB 的用户和角色权限

    副本和分片集群的安全设置参考这个:高级:https://files.cnblogs.com/files/sanduzxcvbnm/mongodb_advance.pdf 默认情况下,MongoDB实例 ...

  7. 用VS Code搞Qt 6:Gui基础类型——QGuiApplication和QWindow

    在99.996%的情况下,我们弄 Qt 应用都会使用 QApplication 类和 QWidget 类,即直接用 Widgets 库中的组件/控件.为了方便开发人员自己造轮子,Qt 也提供了一套基础 ...

  8. WPF开发经验-WPF的TextBox控件的MouseDown事件不响应的解决方法

    一 问题的发现 最近项目有个需求,大概是,当点击某个TextBox时,先执行一些业务上的逻辑处理. 于是按以往思维,将TextBox的MouseDown事件关联事件处理方法,将业务处理写在方法里. 调 ...

  9. C++面向对象编程之类模板、函数模板等一些补充

    1.static数据 和 static函数: 对于 非static函数 在内存中只有一份,当类对象调用时,其实会有该对象的this pointer传进去,那个函数就知道要对那个对象进行操作: stat ...

  10. 使用 Kubeadm 部署 K8S安装

    1. 安装要求 在开始之前,部署Kubernetes集群机器需要满足以下几个条件: 一台或多台机器,操作系统 CentOS7.x-86_x64 硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬 ...