堆
堆(洛谷P3378)
题目大意
建立支持以下三种操作的堆:
- 输入1 x,将x插入堆中
- 输入2,输出堆的最小值
- 输入3,删除堆的最大值
解题思路
手写堆或者使用STL容器实现。
手写堆
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int heap[N],top=0;
void push(int x){
heap[++top]=x;
for(int i=top;i>1&&heap[i]<heap[i>>1];i>>=1)swap(heap[i],heap[i>>1]);
}
void pop(){
heap[1]=heap[top--];
for(int i=1;(i<<1)<=top;){
int son=i<<1;
if(son<top&&heap[son+1]<heap[son])son++;
if(heap[son]<heap[i]){
swap(heap[son],heap[i]);
i=son;
}else break;
}
}
int main(){
int n;
cin>>n;
while(n--){
int op,x;
cin>>op;
if(op==1){
cin>>x;
push(x);
}else if(op==2)cout<<heap[1]<<endl;
else pop();
}
return 0;
}
STL
#include<bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int>>q;
int n;
int main(){
cin>>n;
int op,a;
while(n--){
cin>>op;
switch(op){
case 1:cin>>a;
q.push(a);
break;
case 2:cout<<q.top()<<endl;
break;
case 3:q.pop();
}
}
return 0;
}
合并果子(洛谷P1090)
题目大意
对序列a合并元素至只包含一个元素,合并代价为元素值之和。求最小代价。
解题思路
根据贪心思想,优先合并值小的元素,由于合并后会产生新元素需要更新值,故采用堆即优先队列存储。每次合并最小的两个元素,并将合并值入堆。最后输出总和即可。
未知的代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
priority_queue<int,vector<int>,greater<int>>q;
int n;
int main(){
cin>>n;
int a,ans=0;
while(n--){
cin>>a;
q.push(a);
}
while(q.size()>1){
int x=q.top();
q.pop();
int y=q.top();
q.pop();
ans+=(x+y);
q.push(x+y);
}
cout<<ans<<endl;
return 0;
}
中位数(洛谷P1168)
题目大意
给定一个长度为N的非负整数序列A,对于前奇数项求中位数。
解题思路
使用两个堆,一个大根堆,堆顶存最大值,一个小根堆,堆顶存最小值,这样对于中位数而言小于等于中位数的存放在大根堆,大于的存在小根堆。最后保证大根堆元素数等于小根堆元素数即可。mid即更新为中位数。
未知的代码
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
priority_queue<int>q1; //大根堆
priority_queue<int,vector<int>,greater<int>>q2; //小根堆
int n,mid,x;
cin>>n>>mid;
cout<<mid<<endl; //前1项
for(int i=2;i<=n;i++){
cin>>x;
if(x>mid)q2.push(x);
else q1.push(x);
if(i%2){
while(q1.size()!=q2.size()){
if(q1.size()>q2.size()){
q2.push(mid);
mid=q1.top();
q1.pop();
}else{
q1.push(mid);
mid=q2.top();
q2.pop();
}
}
cout<<mid<<endl;
}
}
return 0;
}
最小函数值(洛谷P2085)
题目大意
给定n个函数\(F_i(x)=A_ix^2+B_ix+C_i\),\(A_i,B_i,C_i\)均给出,均为正整数,求所有函数所有函数值最小的m个,如果最小值有重复需重复输出。
解题思路
由于函数各项系数均为正整数已知函数单调递增,所以对每个函数从1到m取值,计算函数值,使用优先队列存最小值。
未知的代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
int main(){
priority_queue<int>q;
cin>>n>>m;
for(int i=1;i<=n;i++){
int a,b,c;
cin>>a>>b>>c;
for(int j=1;j<=m;j++){
if(i==1)q.push(a*j*j+b*j+c);
else{
int k=a*j*j+b*j+c;
if(k<q.top()){
q.push(k);
q.pop();
}else break;
}
}
}
vector<int>ret;
while(m--){
ret.push_back(q.top());
q.pop();
}
for(int i=ret.size()-1;i>=0;i--)cout<<ret[i]<<" ";
return 0;
}
蚯蚓(洛谷P2827)
题目大意
n条蚯蚓,每秒选最长蚯蚓,设长度为x,按参数p分割为[\(px\)],x-[\(px\)]两条,分割后长度为0的蚯蚓仍然保留,其余蚯蚓每秒长度加一,给定时间m和参数t,输出第t秒,2t秒,\(\dots\),[\(\frac{m}{t}\)]秒的切割前的蚯蚓长度,此外还要输出m秒后,第t,2t,\(\dots\),[\(\frac{(n+m)}{t}\)]长的蚯蚓长度。
解题思路
基于数据范围,只用priority_queue暴力求解会超时,对分割分析可得将蚯蚓分为三类,初始蚯蚓,[\(px\)]和x-[\(px\)]使用三个队列存储这三种蚯蚓,其中初始蚯蚓用优先队列存储,每次取队首元素比较取最长切割。
未知的代码
#include<bits/stdc++.h>
using namespace std;
priority_queue<int>q1;
queue<int>q2,q3;
int n,m,q,u,v,t;
int main(){
cin>>n>>m>>q>>u>>v>>t;
int num;
for(int i=0;i<n;i++){
cin>>num;
q1.push(num);
}
num=0;
for(int i=1;i<=m;i++){
int a,b,c,d=-0x3f3f3f3f;
if(!q1.empty()){
a=q1.top();
d=max(a,d);
}
if(!q2.empty()){
b=q2.front();
d=max(d,b);
}
if(!q3.empty()){
c=q3.front();
d=max(d,c);
}
if(!q1.empty()&&a==d)q1.pop();
else if(!q2.empty()&&b==d)q2.pop();
else if(!q3.empty()&&c==d)q3.pop();
if(i%t==0)cout<<d+num<<" ";
int x=(long long)(d+num)*u/v;
int y=d+num-x;
num+=q;
q2.push(x-num);
q3.push(y-num);
}
cout<<endl;
for(int i=1;i<=n+m;i++){
int a,b,c,d=-0x3f3f3f3f;
if(!q1.empty()){
a=q1.top();
d=max(a,d);
}
if(!q2.empty()){
b=q2.front();
d=max(d,b);
}
if(!q3.empty()){
c=q3.front();
d=max(d,c);
}
if(!q1.empty()&&a==d)q1.pop();
else if(!q2.empty()&&b==d)q2.pop();
else if(!q3.empty()&&c==d)q3.pop();
if(i%t==0)cout<<d+num<<" ";
}
return 0;
}
Cow Coupons G(洛谷P3045)
题目大意
给定n头奶牛售价\(p_i\),现有K张优惠券,购买第i头奶牛其价格将为\(c_i\),每个奶牛只能使用依次优惠券,求使用不超过m元最多买多少奶牛。
解题思路
考虑贪心先以取\(c_i\)价格前k小的和,若此时n小于等于k或加到某一头奶牛价格大于m直接输出答案,若优惠券用完还可继续购买,则需考虑优惠力度,即i使用优惠券比j使用优惠券要优惠更多,需要使用一个优先队列记录\(p_i\)与\(c_i\)差值。
未知的代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int N=5e4+5;
bool vis[N];
priority_queue<ll,vector<ll>,greater<ll>>d;
priority_queue<PII,vector<PII>,greater<PII>>qp,qc;
ll c[N],p[N];
ll n,k,m;
int main(){
int ans=0;
cin>>n>>k>>m;
for(int i=1;i<=n;i++){
cin>>p[i]>>c[i];
qp.push({p[i],i});
qc.push({c[i],i});
}
for(int i=1;i<=k;i++)d.push(0);
while(!qp.empty()){
auto x1=qp.top();
auto x2=qc.top();
if(vis[x1.second]){
qp.pop();
continue;
}
if(vis[x2.second]){
qc.pop();
continue;
}
if(d.top()>x1.first-x2.first){
m-=x1.first;
qp.pop();
vis[x1.second]=true;
}else{
m-=x2.first+d.top();
qc.pop();
d.pop();
vis[x2.second]=true;
d.push(p[x2.second]-c[x2.second]);
}
if(m>=0)ans++;
else break;
}
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号