zoukankan      html  css  js  c++  java
  • 信息奥赛一本通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=maxmin

    【输入】

    第一行,一个数为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;
    }

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

  • 相关阅读:
    【拆点费用流】【HDU1853】【 Cyclic Tour】
    【最小费用最大流】【HDU1533】【Going Home】
    【最大流,二分图匹配】【hdu2063】【过山车】
    【最小费用最大流模板】【Uva10806+Spring Team PK】Dijkstra, Dijkstra,
    【最大流之sap】【HDU1532】模板题
    HDU 6130 Kolakoski 思维个屁 水题
    Codeforces 837 D Round Subset DP 思维
    Educational Codeforces Round 26
    Codeforces Round 427 B The name on the board 水题
    Codeforces Round 428 B Game of the rows 贪心 思维
  • 原文地址:https://www.cnblogs.com/sy666/p/12815247.html
Copyright © 2011-2022 走看看