【笔记】CF1251E Voting 及相关
题目传送门
贪心:
一个人 \(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 及相关的更多相关文章
- amazeui学习笔记--css(布局相关1)--网格Grid
amazeui学习笔记--css(布局相关1)--网格Grid 一.总结 基本使用 1.div+class布局:amaze里面采取的就是div+class的布局方式 <div class=&q ...
- amazeui学习笔记--css(布局相关3)--辅助类Utility
amazeui学习笔记--css(布局相关3)--辅助类Utility 一.总结 1.元素清除浮动: 添加 am-cf 这个 class 即可 2.水平滚动: .am-scrollable-horiz ...
- amazeui学习笔记--css(布局相关2)--等分网格 AVG Grid
amazeui学习笔记--css(布局相关2)--等分网格 AVG Grid 一.总结 1.与grid区别:网格中:am-g + am-u-xx-n 等分网格中只有一个: am-avg-sm-4(在u ...
- 11G RAC 中 OCR 及Voting Disk 相关操作
一.启动oracle clusterware先决条件:Oracle High Availability Services daemon(OHASD)运行在所有集群节点上1.启动整个Oracle Clu ...
- shell 脚本实战笔记(7)--集群网络相关知识和环境搭建
前言: 对网络相关的知识, 做下笔记. 包括IP地址A/B/C的分类, 静态地址的配置/DNS配置, 以及网卡相关信息查看. *) A/B/C/D类网络地址的划分 IP地址=网络地址+主机地址 或 I ...
- ElasticSearch学习笔记-02集群相关操作_cat参数
_cat参数允许你查看集群的一些相关信息,如集群是否健康,有哪些节点,以及索引的情况等的. 检测集群是否健康 curl localhost:9200/_cat/health?v 说明: curl 是一 ...
- [开发笔记]-Windows Service服务相关注意事项
注意一:报错:“本地计算机上的 *** 服务启动后停止.某些服务在未由其他服务或程序使用时将自动停止.” 该问题主要的原因是 Service服务程序中有错误. 遇到这个问题时,无论是重新安装服务,还是 ...
- CentOS学习笔记--基本命令--目录的相关操作
Linux基本命令--目录的相关操作 常见的处理目录的命令吧: cd:变换目录 pwd:显示目前的目录 mkdir:创建一个新的目录 rmdir:删除一个空的目录 cd (变换目录) cd是Chang ...
- LoRaWAN_stack移植笔记(一)--RF硬件相关
和硬件相关的问题 TCXO 的使用 根据SX1276数据手册, 如果使用TCXO,则需要配置RegTcxo寄存器为0x19,代码如下 ``` c void SX1276SetTcxoConfig(vo ...
随机推荐
- 几款优秀的点播、RTSP/RTMP直播播放器介绍
1.ijkplayer 项目地址: https://github.com/Bilibili/ijkplayer 介绍:Ijkplayer 是Bilibili发布的基于 FFplay 的轻量级 Andr ...
- GreatSQL vs MySQL性能测试来了,速围观~
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. GreatSQL是MySQL的国产分支版本,使用上与MySQL一致. 1.结论先行 无论ibp(innodb_buffer ...
- day41-网络编程03
Java网络编程03 5.UDP网络通信编程[了解] 5.1基本介绍 类DatagramSocket 和 DatagramPacket[数据报/数据包]实现了基于 UDP的协议网络程序 UDP数据报通 ...
- Kubernetes 日志:日志收集架构
应用程序和系统日志可以帮助我们了解集群内部的运行情况,日志对于我们调试问题和监视集群情况也是非常有用的.而且大部分的应用都会有日志记录,对于传统的应用大部分都会写入到本地的日志文件之中.对于容器化应用 ...
- MySQL8.0报错:Access denied; you need (at least one of) the SYSTEM_USER privilege(s) for this operation
MySQL8.0.16版本中新增了一个system_user帐户类型,当新增用户并赋予权限时 mysql> create user 'proxysql'@'192.168.20.%' ident ...
- 在云原生中监控JVM指标
一般 Java 集成 Prometheus 监控指标有两种方式.一种是依赖中引入,另外一种是通过agent执行. 依赖引入 <!-- The client --> <dependen ...
- 8.第七篇 验证kube-apiserver及kubeconfig配置详解
文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247483818&idx=1&sn=7572b791 ...
- Dockerfile文件:设置变量启动的时候传递进去
from openjdk:8-jdk-alpine RUN ln -sf /usr/share/zoneinfo/Asia/shanghai /etc/localtime RUN echo 'Asia ...
- k8s更换网络插件:从flannel更换成calico
卸载flannel 查看已安装的flannel的信息 # 查看CNI插件,可以得知使用的是flannel # cat /etc/cni/net.d/10-flannel.conflist { &quo ...
- Spring Boot 使用 Micrometer 集成 Prometheus 监控 Java 应用性能
转载自:https://cloud.tencent.com/developer/article/1508319 文章目录1.Micrometer 介绍2.环境.软件准备3.Spring Boot 工程 ...