7-8 合并石子 (20分) 合并石子
现在有n堆石子,我们要把它们合并成一堆。 每一次合并,可以把两堆石子(可以不相邻)合并到一起, 消耗的体力等于两堆石子的重量之和。
可以看出,所有的石子经过 n−1 次合并之后,就只剩下一堆了。 在合并石子时总共消耗的体力等于每次合并所耗体力之和。我们在合并石子时要尽可能地节省体力。假定每个石子重量都为1 , 并且已知石子的堆数和每堆石子的数目,求最少所消耗的体力。
输入格式:
共两行。 第一行是一个整数 n(1≤n≤100000) ,表示石子的堆数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 ai(0≤ai≤100000) 是第 i 堆石子的数目。
输出格式:
一个整数,也就是最小的体力耗费值。
输入样例:
3 1 2 3
输出样例:
9
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<vector>
#include<string>
#define M 100010
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int n;
int main(){
cin >> n;
priority_queue<int,vector<int>,greater<int> >q;
int t;
while(n--){
scanf("%d",&t);
q.push(t);
}
ll ans = 0;
while(q.size()>1){
ll now = 0;
now += q.top(); q.pop();
now += q.top(); q.pop();
q.push(now);
ans += now;
}
cout << ans << endl;
return 0;
}
自己原本思路:让最轻的移动次数最多
eg
1 2 3
分别需要移动2 2 1次
错误:这个思路是先从最轻的开始,固定住目标堆,其余依次被放入
eg 2 2 3 3
此做法:
(2,2)3 3——(4),3,3————4
(4,3) 3——(7,3)————7
(7,3)——10
总计 21
但是实际上最少:每次动态把最轻的拿出来
(2,2)3,3——3,3,4————4
(3,3)4——4,6————6
(4,6)————10
共计 20
int n;
int a[M];
int main(){
cin >> n;
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
sort(a,a+n);
ll ans = 0;
for(int i=0; i<n; i++)
ans += a[i]*(n-i);
ans -= a[0];
cout << ans << endl;
return 0;
}
合并石子2
现在有n堆石子,我们要把它们合并成一堆。 每一次合并,只能把相邻的两堆石子合并到一起, 消耗的体力等于两堆石子的重量之积。
可以看出,所有的石子经过 n−1 次合并之后,就只剩下一堆了。 在合并石子时总共消耗的体力等于每次合并所耗体力之和。我们在合并石子时要尽可能地浪费体力。假定每个石子重量都为1 , 并且已知石子的堆数和每堆石子的数目,求最多所消耗的体力。
输入格式:
共两行。 第一行是一个整数 n(1≤n≤100000) ,表示石子的堆数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 ai(0≤ai≤10000) 是第 i 堆石子的数目。
数据保证最终答案在长整型范围以内。
输出格式:
一个整数,也就是最多的体力耗费值。
输入样例:
3 1 2 3
输出样例:
11
合并石子时要尽可能地浪费体力
先合并轻的还是先合并重的:
eg
1 2 3 10
3,3,10——2
6,10——9
16——60——71
1,2,13——30
1,15——26
16——15——71
发现:不管怎么合并都一样:
原因:
eg a b c d-----ab + ac+ ad +bc+ bd +cd
每个石子都乘上了除自己之外的所有石子,所以不管怎么合并,都同
边输入遍运算即可
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<vector>
#include<string>
#define M 100010
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int main(){
ll n,now,pre=0;
ll ans = 0;
cin >> n;
while(n--){
scanf("%lld",&now);
ans += now*pre;
pre += now;
}
cout << ans << endl;
return 0;
}