堆(洛谷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;
}
posted @ 2023-12-29 12:58  Lost-in-love  阅读(39)  评论(0)    收藏  举报