题目描述
125.极差 (15分)
C时间限制:3000 毫秒 | C内存限制:3000 K
题目内容:
在黑板上写了N个正整数组成的一个数列,进行如下操作:每次擦去其中的两个数a和b,
然后在数列中加入一个数a*b+1,如此下去直至黑板上剩下一个数,在所有按这种操作方式
最后得到的数中,最大的为max,最小的为min,则该数列的极差定义为M=max-min.请你编程,
对于给定的数列,计算极差.输入描述
输入包含多个测试集.每个测试集的第一行N表示正整数序列长度(0<=N<=50000),随后第二行是N个正整数.当N为0时结束.
输出描述
每个结果一行.
输入样例
3
3 5 7
输出样例
4
解题思路
当a+b为一个常数时
均值不等式 sqrt(ab)<=(a+b)/2;所以当a==b时 ab最大
如果要求最大值的话,那么每次先用最小的两个数相乘的结果+1,(缩小乘积因子之间的差)
相反,如果要求最小值的话,每次先用最大的两个数相乘的结果+1(大的数就越大,扩大乘积因子之间的差)例子:数列2,4,6.按照极差的定义,我们算算这个数列的极差。
有三种情况:(2*4+1)*6+1=55,(4*6+1)*2+1=51,(6*2+1)*4+1=53我们发现当先算两个较小的数是,
得到的是最大值,当先算两个较大的数时,得到的是最小值。这里运用优先队列取用最大最小数,总时间复杂度O(nlog(n))
AC代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int N = 50005;
priority_queue<ll,vector<ll>,less<ll> > maxQ;//最大堆
priority_queue<ll,vector<ll>,greater<ll> > minQ;//最小堆
int n;
ll x;
ll maxAns;
ll minAns;
void solve(){//时间复杂度nlogn
ll a,b;
for(int i=0;i<n-1;i++){//求最小值
a=maxQ.top();maxQ.pop();
b=maxQ.top();maxQ.pop();
maxQ.push(a*b+1);
}
for(int i=0;i<n-1;i++){
a=minQ.top();minQ.pop();
b=minQ.top();minQ.pop();
minQ.push(a*b+1);
}
printf("%lld\n",minQ.top()-maxQ.top());
}
int main(){
while(~scanf("%d",&n)){
while(!maxQ.empty()) maxQ.pop();
while(!minQ.empty()) minQ.pop();
for(int i=0;i<n;i++){
scanf("%lld",&x);
maxQ.push(x);
minQ.push(x);
}
solve();
}
return 0;
}