题目传送门

贪心:

一个人 \(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. vscode 快速注释和撤回快捷键

    好家伙,天天忘,建议先练个十遍上手 1.快捷行注释 Ctrl + / 2.快捷块注释 Alt + Shift + A 3.撤回 Ctrl + Z 4.恢复撤回(撤回你的撤回) Ctrl + Shift ...

  2. Arrays.asList()你真的知道怎么用吗?

    发现问题 前几天在看别人的项目的时候,发现一个问题,简单复现一下这个问题 // 注意这是一个Integer对象的数组哦 Integer[] arr = new Integer[]{9999,88,77 ...

  3. Docker安装Openresty总结

    1. 启动Docker systemctl start docker 2. 查询有没有openresty镜像 docker search openresty -s 30 -s 30 stars数大于3 ...

  4. 【读书笔记】C#高级编程 第十二章 动态语言扩展

    (一)DLR C#4的动态功能是Dynamic Language Runtime(动态语言运行时,DLR)的一部分.DLR是添加到CLR的一系列服务. (二)dynamic类型 dynamic类型允许 ...

  5. 怎么用vscode创建工程

    以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/p/16685082.html vs code创建工程,以k ...

  6. 头文件与main函数

    头文件 1.为什么要使用头文件? 程序如戏 程序中有很多元素(std::cout, system), 都是一个个演员 但是他们之间都互不认识, 但是却要一起合作, 强行编译, 就会导致错误! 得预先介 ...

  7. 【学习笔记】Vin-Mono论文阅读笔记(一)

    VINS-Mono 概述 VINS-Mono VINS-Mono是由一个单目相机和一个低成本IMU组成的鲁棒通用的单目视觉惯性系统.通过融合预积分的IMU测量值和特征观测值来获得高精度的视觉惯性里程计 ...

  8. Logstash: 启动监控及集中管理

    在本篇文章里,我将详细介绍如果启动Logstash的监控及集中管理. 前提条件 安装好Logstash,设置Elasticsearch及Kibana的安全密码. 如何监控Logstash? 我们安装如 ...

  9. 使用Portainer 部署WordPress容器

    安装WordPress容器 进入到 Portainer 页面,选择左边的 Containers 选项,单击上方的 Add container 按钮转到如图所示的页面: 1.在 Name 一栏中输入容器 ...

  10. 【C++】从零开始的CS:GO逆向分析1——寻找偏移与基址的方法

    [C++]从零开始的CS:GO逆向分析1--寻找偏移与基址的方法   前言:此文章主要用于提供方法与思路,fps游戏基本都能如此找偏移,文章里找的偏移比较少,主要用来演示寻找思路,文章的后记中会附一个 ...