P6033,P1090
题目大意
给出一个数组,每次合并两个元素,并将这两个元素的和累加至一个变量,输出当这个数组只剩一个元素时该变量的最小值。
思路
数据范围一改这道题的难度直接从黄色变成了绿色,首先考虑黄色的解法,很简单,我们可以轻易证明每次把最小的俩加起来就可以了,但怎么筛呢?两种法子,一种直接排序,用什么排?这里值域小能用桶排。一种用优先队列,他可以直接把最小的推到最前面来。这两种一种是值域的复杂度,一种是n log n的复杂度,显然能过基础版,一看果然ac,不难的。
传到了6033,忘了开longlong导致30pt,改成longlong就60pt,那怎么提升呢?
看了题解,题解里面用两个队列来实现了O(n),个人感觉比较麻烦的,我直接贴代码了,不过这里面还说要是有可能的话可以用另一种数据类型代替pq,不确定,一会补。
代码
P1090 ac代码 P6033 60pt 代码
#include<bits/stdc++.h>
using namespace std;
int n,x,ans;
priority_queue<int,vector<int>,greater<int> >q;
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>x,q.push(x);
while(q.size()>=2){
int a=q.top(); q.pop();
int b=q.top(); q.pop();
ans+=a+b;
q.push(a+b);
}
cout<<ans<<endl;
return 0;
}
P6033 ac
#include<bits/stdc++.h>
using namespace std;
inline long long read()
{ long long x=0;
bool f=0;
char c=getchar();
while(!isdigit(c))f|=(c=='-'),c=getchar();
while(isdigit(c))x=x*10+(c&15),c=getchar();
return f?-x:x;
}
queue<long long> q1,q2;//两个队列,q1维护原先的果子,q2维护合并成一堆的果子。
long long tong[100005],n,ans;//不开long long见祖宗
signed main()
{ n=read();
for(register long long i=1;i<=n;++i)//桶排
{ int x=read();
tong[x]++;
}
for(register long long i=1;i<=100000;++i)
{ while(tong[i])
{ tong[i]--;
q1.push(i);//加入
}
}
for(register long long i=1;i<n;++i)
{ long long x,y;
//接下来四个比较。
if((q1.front()<q2.front()&&!q1.empty())||q2.empty())
{ x=q1.front();
q1.pop();
}
else
{ x=q2.front();
q2.pop();
}
if((q1.front()<q2.front()&&!q1.empty())||q2.empty())
{ y=q1.front();
q1.pop();
}
else
{ y=q2.front();
q2.pop();
}
ans+=(x+y);//ans加值
q2.push(x+y);//将合并的果子加入到q2。
}
printf("%lld",ans);
return 0;
}