洛谷 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;
}