题目连接:该题是luogu试炼场的2-6:T1
题目大意:
1 给n个数字的序列,(每次取最小的两个相加,得到新的数字),这个数字再放回原序列,直到序列里只有一个数;
2 求:过程中产生的和的总量;
3 例如:
原序列为:1 2 3 5;
1+2=3: 新序列为:3 3 5;
3+3=6: 新序列为:5 6;
5+6=11:新序列为:11.
所以答案是:3+6+11=20.
解题思路:
1 因为数字是可以随意调换顺序的,所以每次都是要找最小值出来,因此想到了堆;
2 用一个堆来维护这些数字,每次取最小值,然后把加好的新值放回堆中;
3 直到堆里值剩下一个元素,记录过程的和就好了。
上代码:
//luogu1181:数列分段
//解题思路:
//1 一用一个堆维护最小值
//2 每次取最小的两个值相加
//3 直到全部合并
#include<cstdio>
#include<cstring>
int n;
int a[10010];
void sdown(int x)//向下的维护堆
{
int f,s,t=x;
f=x; s=f*2;
if(s<=n && a[f]>a[s]) t=s; //问 左儿子
if(s+1<=n && a[t]>a[s+1]) t=s+1;//问 右儿子
if(t!=x) //要交换
{
int k=a[f]; a[f]=a[t]; a[t]=k;
sdown(t);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=n/2;i>=1;i--) //建堆
{
sdown(i);
}
int ans=0,k;
while(n>1)//堆还有多个元素
{
k=0;
ans+=a[1]; k+=a[1]; //拿第一个数
a[1]=a[n]; n--; sdown(1); //维护
ans+=a[1]; k+=a[1]; //拿第二个数
a[1]=k; sdown(1); //维护
}
printf("%d",ans);
return 0;
}