问题描述
在黑板上写了N个正数组成的一个数列,进行如下操作:每一次擦去其中2个数,设为a和b,然后在数列中加入一个数 a × b + 1 a\times b+1 a×b+1,如此下去直至黑板上只剩下一个数。在所有按这种操作方式最后得到的数中,最大的数记为max,最小的数记为min,则该数列的极差M定义为M=max-min。
测试样例
输入1:
3
3 5 7
输出1:
4
输入2:
3
1 2 3
输出2:
2
算法原理
本题使用贪心算法求解:
- 求最大值时,不断从数组中抽取最小的两个数乘积再加一,然后放入数组,不断重复这个过程,直到数组中只剩一个数,就是最大值。但是每次新加入的元素都要进行排序,这里我使用最小堆优化,不断抽取堆顶元素即可。
- 求最小值时,不断从数组中抽取最大的两个数乘积再加一,然后放入数组,不断重复这个过程,直到数组中只剩一个数,就是最小值。由于每次抽取的两个最大值计算出来的结果一定比其余的数都要大(所有数都是正数),因此只需要在最开始排序一次,后续计算直接往最后面放就能维持整个数组有序。
算法实现
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
void main() {
priority_queue<int, vector<int>, greater<int>> minq;
vector<int> maxv;
int n, min, max;
cin >> n;
for (int i = 0; i < n; i++) {
int temp;
cin >> temp;
minq.push(temp);
maxv.push_back(temp);
}
sort(maxv.begin(), maxv.end());//默认从小到大
while (minq.size() > 1) {
int a = minq.top();
minq.pop();
int b = minq.top();
minq.pop();
minq.push(a * b + 1);
}
max = minq.top();
//找最小值不用再排序,因为每次都取最大值乘积加一,绝对比所有数都大,直接放最后就行
for (int i = 0; i < n-1; i++) {
maxv[n - i - 2] = maxv[n - i - 1] * maxv[n - i - 2] + 1;
}
min = maxv[0];
cout << "max=" << max << "\nmin=" << min << endl;
cout << max - min;
}