个人练习总结2

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

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值