洛谷 P6033 [NOIP2004 提高组] 合并果子 加强版(桶排序,队列)

传送门


解题思路

经典题的加强版。
根据数据范围得出需要O(n)解决这个问题。
至少要进行一次排序,而且数字<=1e5,所以很显然可以桶排。
然后用两个队列(注意不是优先队列),一个是存原数,一个存和。
每次取出两个队列中前二的两个数字,然后加起来放到第二个队列的队尾即可。
易证两个队列里面的数都满足单调性。
手写队列会很简单,但我就用stl,于是写了死长的代码还有各种判断。
唉,就是玩儿~

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1e5+5;
int n,a,maxa,c[maxn];
long long ans,a1,a2;
queue<long long> q1,q2;
int read(){
	int res=0;
	char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9'){
		res=res*10+c-'0';
		c=getchar();
	}
	return res;
} 
int main(){
	ios::sync_with_stdio(false);
	n=read();
	for(int i=1;i<=n;i++) a=read(),maxa=max(maxa,a),c[a]++;
	for(int i=1;i<=maxa;i++){
		while(c[i]--) q1.push(i);
	}
	if(n==1){
		cout<<q1.front()<<endl;
		return 0;
	}
	a1=q1.front();
	q1.pop();
	ans+=q1.front()+a1;
	q2.push(q1.front()+a1);
	q1.pop();
	while(!q1.empty()){
		if(q1.front()>q2.front()){
			a1=q2.front();
			q2.pop();
		}else{
			a1=q1.front();
			q1.pop();
		}
		if(q1.empty()){
			a2=q2.front();
			q2.pop();
		}else{
			if(q2.empty()){
				a2=q1.front();
				q1.pop();
			}else{
				if(q1.front()>q2.front()){
					a2=q2.front();
					q2.pop(); 
				}else{
					a2=q1.front();
					q1.pop();
				}
			}
		}
		ans+=a1+a2;
		q2.push(a1+a2);
	}
	while(!q2.empty()){
		a1=q2.front();
		q2.pop();
		if(q2.empty()) break;
		a2=q2.front();
		q2.pop();
		ans+=a1+a2;
		q2.push(a1+a2);
	}
	cout<<ans;
    return 0;
}
posted @ 2021-09-14 21:54  尹昱钦  阅读(121)  评论(0编辑  收藏  举报