信息奥赛一本通1427:数列极差

题目链接:http://ybt.ssoier.cn:8088/problem_show.php?pid=1427

1427:数列极差


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 1681     通过数: 757

【题目描述】

在黑板上写了N个正整数作成的一个数列,进行如下操作:每一次擦去其中的两个数a和b,然后在数列中加入一个数a×b+1,如此下去直至黑板上剩下一个数,在所有按这种操作方式最后得到的数中,最大的max,最小的为min,则该数列的极差定义为M=max−min。

【输入】

第一行,一个数为N;

第二行,N个数。

【输出】

输出极差。

【输入样例】

3
1 2 3

【输出样例】

2

【来源】

No

 

这个题是一道贪心题。

先建一个堆,求最大值的过程就是从堆中选出两个最小的数,再将这两个数相乘+1加入堆,

求最小值的过程就是从堆中选出两个最大的数,再将这两个数相乘+1加入堆。

以求最大值为例:

一个比较通俗的证明

  先选两个小的数,因为要+1,让这个1与更大数相乘能让它更大,所以每次合并都尽量和最小的。

一个较清晰的证明

  假设有3个数a,b,c(a<=b<=c)则三种合并顺序abc,acb,bca,所得值分别为(a*b+1)*c+1=a*b*c+c+1,(a*c+1)*b+1=a*b*c+b+1,(b*c+1)*a+1=a*b*c+a+1,

  显然a*b*c+c+1最大,更多的数也是如此,所以每次合并都尽量和最小的。

求最小值就是把求最大值的过程反过来。

题目中要求分别建大根堆和小根堆,可以用函数指针,让它分别等于a>b函数指针和a<b函数指针,这样就不用把堆的代码打两遍(其实复制粘贴在改几个地方也可以)。

代码:

 

#include<stdio.h>
long long a[100001],b[100001],maxx,minn,a1,a2;
int lena,n;
int (*cmp)(long long,long long);//比较的函数指针
int dgd(long long aaa,long long bbb){//大根堆比较
    return aaa>bbb;
}
int xgd(long long aaa,long long bbb){//小根堆比较
    return aaa<bbb;
}
long long geta(){//从堆中弹出一个元素
    int now,next;
    long long res,p;
    res=a[1];
    a[1]=a[lena--];
    now=1;
    while((now<<1)<=lena){
        next=now<<1;
        if(next<lena&&(*cmp)(a[next+1],a[next]))next++;
        if((*cmp)(a[now],a[next]))break;
        p=a[now];a[now]=a[next];a[next]=p;
        now=next;
    }
    return res;
}
void puta(long long res){//从堆中加入一个元素
    int now,next;
    long long p;
    a[++lena]=res;
    now=lena;
    while(now>1){
        next=now>>1;
        if((*cmp)(a[next],a[now]))break;
        p=a[now];a[now]=a[next];a[next]=p;
        now=next;
    }
    return;
}
int main(){ 
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld",b+i);
    cmp=xgd;//计算最大值
    for(int i=1;i<=n;i++)puta(b[i]);
    while(lena>1){
        a1=geta();
        a2=geta();
        puta(a1*a2+1);
    }
    maxx=geta();
    cmp=dgd;//计算最小值
    for(int i=1;i<=n;i++)puta(b[i]);
    while(lena>1){
        a1=geta();
        a2=geta();
        puta(a1*a2+1);
    }
    minn=geta();
    printf("%lld",(maxx-minn));
    return 0;
}

 我可能写的不好,如果有问题,请帮忙指出,谢谢。

上一篇:UVA 11731 Ex-circles


下一篇:go和c混编