1083. 数列极差问题
题目描述
在黑板上写了NNN个正整数组成的一个数列,进行如下操作: 每次擦去其中的两个数 a
和 b
,然后在数列中加入一个数a×b+1a \times b+1a×b+1,如此下去直至黑板上 剩下一个数,在所有按这种操作方式最后得到的数中,最大的为 maxmaxmax,最小的为 minminmin , 则该数列的极差定义为 M=max-minM=max-minM=max-min。
请你编程,对于给定的数列,计算极差 mmm。
输入
第一行是数列的长度n(不超过10),第二行起是数列中n个数,相邻2个数由空格分开;
每个数均不超过100.
输出
输出一个整数表示数列极差m
样例输入
3
1 2 3
样例输出
2
思路
题目中有这个东西: 每次 擦去 其中的两个数 aaa 和 bbb,然后在数列中加入一个数 a×b+1a \times b+1a×b+1
这不就是哈夫曼编码的建立过程吗? 所以我们根据贪心策略,当然每次选择最小的整数相乘自然会更好呀?
什么? 你想要证明?这个和哈夫曼编码的证明的方法是一样的,最好的方法当然是上网搜索啦 (其实太复杂了,作者不会qwq)
Step1: 定义堆
priority_queue<int> q1;
priority_queue<int, vector<int>, greater<int>> q2;
q1 里面的元素是越大的在前面,q2 就是越小的在前面
注意: q2的定义后面的两个 “>>” 符号在编译的时候要使用 C++11 编译,要使用 C++11 提交,如果不想这样,可以加一个空格,比如:
priority_queue<int, vector<int>, greater<int> > q2;
Step2: 主程序计算
int Max = 0, Min = 0;
while (q1.size() > 1)
{int p = q1.top(); q1.pop();int q = q1.top(); q1.pop(); q1.push(p * q + 1);
}
Min = q1.top();while (q2.size() > 1)
{int p = q2.top(); q2.pop();int q = q2.top(); q2.pop();q2.push(p * q + 1);
}
Max = q2.top();printf("%d", Max - Min);
push: 表示将元素 i 插入堆
pop: 表示删除最大/最小的元素
top: 表示取最大的元素
Step3: 完整代码
#include <stdio.h>
#include <queue>using namespace std;int n;
priority_queue<int> q1;
priority_queue<int, vector<int>, greater<int>> q2;
int main()
{int n;scanf("%d", &n);for (int i = 1; i <= n; i++){int x;scanf("%d", &x);q1.push(x), q2.push(x);}int Max = 0, Min = 0;while (q1.size() > 1){int p = q1.top(); q1.pop();int q = q1.top(); q1.pop();q1.push(p * q + 1);}Min = q1.top();while (q2.size() > 1){int p = q2.top(); q2.pop();int q = q2.top(); q2.pop();q2.push(p * q + 1);}Max = q2.top();printf("%d", Max - Min);return 0;
}
时间复杂度分析
堆的 push
是 O(logn)O(\log n)O(logn) 的,但是这道题的数列的长度是 101010, 完全足够
运行时间只有 0.1s0.1s0.1s, 因为机器的每秒钟运算大概是 10810^8108, 0.1s0.1s0.1s 大约就是 10710^7107 左右,那么这个程序的时间复杂度是 O(nlogn)O(n \log n)O(nlogn) 在最大规模是 101010 的情况下大约要进行 303030 次运算(太快了,oj 上跑出了 0ms0 ms0ms)