时间限制:1000MS 代码长度限制:10KB
提交次数:25 通过次数:9
题型: 编程题 语言: G++;GCC;VC;JAVA

有n堆石子形成一行(a1,a2,…,an,ai为第i堆石子个数),现要将石子合并成一堆,规定每次可
选择至少2堆最多k堆移出然后合并,每次合并的分值为新堆的石子数。
若干次合并后,石子最后肯定被合并为一堆,得分为每次合并的分值之和。
现在求解将这n堆石子合并成一堆的最低得分和最高得分。
两行。第一行n和k。
第二行a1 a2 … an,每个ai(1<=i<=n)表示第i堆石子的个数,n<=200,2<=k<=n。
仅一行,为石子合并的最低得分和最高得分,中间空格相连。
7 3
45 13 12 16 9 5 22
199 593
保证每次选两堆最多的,合并直至只剩一堆为止,能获得最大得分;

更多注释可查看下方的完整代码中,有助于理解。
#include
#include
/*
7 3
45 13 12 16 9 5 22
*/
using namespace std;
int a[201]; // 用于求最大得分的数据
int b[201]; // 用于求最小得分的数据
int n, k;
int minNum = 0, maxNum = 0;
bool cmp2(int lhs,int rhs)//降序
{
return lhs > rhs;
}
void Max() {
int i;
for (i = n - 1; i > 0; i--)
{
a[i - 1] += a[i];
maxNum += a[i - 1];
}
}
void Min() {
// 每次合并 k 堆,最后不能刚好合并完时,就得添加到最后一次刚好合并完,即如果差1堆,就得补1个0
int i, j;
for (i = n - 1; i > 0; i = i - k + 1)
{
// 每次合并 k 堆,然后将合并后的得分记上
for(j = 0; j < k - 1; j++) {
b[i - k + 1] += b[i - j];
}
minNum += b[i - k + 1];
sort(b, b + i - k + 2, cmp2); // 每次加完后都要重新排序,注意已加过的那些石堆就不用排序了,截止位置为 i - k + 1 的位置再加上一个1,因为是尾部开区间
}
}
int main()
{
int i;
cin >> n >> k;
for(i = 0; i < n; i++) {
cin >> a[i];
b[i] = a[i];
}
sort(a, a + n); // 升序排序
Max();
while ((n % (k - 1)) != 1) {
b[n] = 0;
n++;
}
sort(b, b + n, cmp2);
Min();
cout << minNum << " " << maxNum << endl;
return 0;
}