zoukankan      html  css  js  c++  java
  • 蓝桥杯 历届试题 小朋友排队(数状数组+离散化||归并排序||线段树+离散化)

    Description

    n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。
    每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。
    如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。
    请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
    如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。

    Input

    输入的第一行包含一个整数n,表示小朋友的个数。
    第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。

    Output

    输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。

    Sample Input

    3
    3 2 1

    Sample Output

    9

    Hint

    【样例说明】
       首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。
    【数据规模与约定】
        对于10%的数据, 1<=n<=10;
        对于30%的数据, 1<=n<=1000;
        对于50%的数据, 1<=n<=10000;
        对于100%的数据,1<=n<=100000,0<=Hi<=1000000。

    Source

    蓝桥杯
     
    对每个数字,求出前面比他大的数字个数+后面比他小的数字个数,就是需要该数字需要交换的次数
    每个人的不开心度就是首项是1,尾项是交换次数,d=1的等差数列的和
    所以就是对每个数字进行一次等差数列的求和:(a1+d)*an/2
    所以我们的重点是统计每个数字需要交换的次数
    开始想的是冒泡
    但我们冒泡肯定会超时
    所以采用树状数组
    快很多!
     
    具体分析:
    用一个计数数组,数组的下标存输入的数字,先从头开始遍历,出现一次就加一,输入一次就统计前面大于该数字的数出现的次数:当前数字的个数i-前面小于等于该数字的个数
    所以树状数组和线段树都是可以的
     
    code:
    树状数组
    没有离散化的代码:
    #include<stdio.h>
    #include<iostream>
    #include<math.h>
    #include<string.h>
    #include<set>
    #include<map>
    #include<list>
    #include<math.h>
    #include<queue>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    #define INF 99999999
    #define me(a,x) memset(a,x,sizeof(a))
    int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
    int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
    
    int getval()
    {
        int ret(0);
        char c;
        while((c=getchar())==' '||c=='
    '||c=='
    ');
        ret=c-'0';
        while((c=getchar())!=' '&&c!='
    '&&c!='
    ')
            ret=ret*10+c-'0';
        return ret;
    }
    void out(int a)
    {
        if(a>9)
            out(a/10);
        putchar(a%10+'0');
    }
    
    #define max_v 1000005
    LL a[max_v];
    LL b[max_v];
    LL c[max_v];
    LL maxx;
    int n;
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int x,int d)
    {
        while(x<=maxx)
        {
            c[x]+=d;
            x+=lowbit(x);
        }
    }
    int getsum(int x)//前面小于等于x的个数
    {
        int res=0;
        while(x>0)
        {
            res+=c[x];
            x-=lowbit(x);
        }
        return res;
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            LL ans=0;
            memset(c,0,sizeof(c));
            memset(b,0,sizeof(b));
            maxx=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&a[i]);
                a[i]++;//防止有0,都偏移一个单位不影响结果
                maxx=max(maxx,a[i]);
            }
            for(int i=1;i<=n;i++)//先更新再统计
            {
                update(a[i],1);
                b[i]+=((i-getsum(a[i])));//前面大于x的个数:当前数字个数i减去数列前面小于等于a[i]的数的个数
            }
            memset(c,0,sizeof(c));
            for(int i=n;i>=1;i--)//序列反向
            {
                update(a[i],1);
                b[i]+=getsum(a[i]-1);//后面小于x的个数:小于等于a[i]-1的数的个数就是小于a[i]的数的个数
            }
            for(int i=1;i<=n;i++)
            {
                ans+=((b[i]+1LL)*b[i]/2LL);//n个等差数列求和
            }
            printf("%lld
    ",ans);
        }
    }

     离散化的树状数组代码(离散化:数据范围压缩,但数据间的相对关系没有改变)

    #include<stdio.h>
    #include<iostream>
    #include<math.h>
    #include<string.h>
    #include<set>
    #include<map>
    #include<list>
    #include<math.h>
    #include<queue>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    #define INF 99999999
    #define me(a,x) memset(a,x,sizeof(a))
    int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
    int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
    
    int getval()
    {
        int ret(0);
        char c;
        while((c=getchar())==' '||c=='
    '||c=='
    ');
        ret=c-'0';
        while((c=getchar())!=' '&&c!='
    '&&c!='
    ')
            ret=ret*10+c-'0';
        return ret;
    }
    void out(int a)
    {
        if(a>9)
            out(a/10);
        putchar(a%10+'0');
    }
    
    #define max_v 1000005
    struct node
    {
        LL v,pos;
    }p[max_v];
    bool cmp(node x,node y)
    {
        if(x.v!=y.v)
            return x.v<y.v;
        else
            return x.pos<y.pos;
    }
    LL b[max_v];
    LL c[max_v];
    LL n;
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int x,int d)
    {
        while(x<=n)
        {
            c[x]+=d;
            x+=lowbit(x);
        }
    }
    int getsum(int x)//前面小于等于x的个数
    {
        int res=0;
        while(x>0)
        {
            res+=c[x];
            x-=lowbit(x);
        }
        return res;
    }
    int main()
    {
        while(~scanf("%lld",&n))
        {
            LL ans=0;
            memset(c,0,sizeof(c));
            memset(b,0,sizeof(b));
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&p[i].v);
                p[i].pos=i;
            }
            sort(p+1,p+1+n,cmp);//离散化
            
            for(int i=1;i<=n;i++)//先更新再统计
            {
                update(p[i].pos,1);
                b[i]+=((i-getsum(p[i].pos)));//前面大于x的个数:当前数字个数i减去数列前面小于等于a[i]的数的个数
            }
            memset(c,0,sizeof(c));
            for(int i=n;i>=1;i--)//序列反向
            {
                update(p[i].pos,1);
                b[i]+=getsum(p[i].pos-1);//后面小于x的个数:小于等于a[i]-1的数的个数就是小于a[i]的数的个数
            }
            for(int i=1;i<=n;i++)
            {
                ans+=((b[i]+1LL)*b[i]/2LL);//n个等差数列求和
            }
            printf("%lld
    ",ans);
        }
    }

     归并排序:

    #include<stdio.h>
    #include<iostream>
    #include<math.h>
    #include<string.h>
    #include<set>
    #include<map>
    #include<list>
    #include<math.h>
    #include<queue>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    #define INF 99999999
    #define me(a,x) memset(a,x,sizeof(a))
    int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
    int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
    
    LL getval()
    {
        LL ret(0);
        char c;
        while((c=getchar())==' '||c=='
    '||c=='
    ');
        ret=c-'0';
        while((c=getchar())!=' '&&c!='
    '&&c!='
    ')
            ret=ret*10+c-'0';
        return ret;
    }
    void out(int a)
    {
        if(a>9)
            out(a/10);
        putchar(a%10+'0');
    }
    
    #define max_v 100005
    struct node
    {
        LL v,num;
    } p[max_v],temp[max_v];
    void mer(int s,int m,int t)
    {
        int i=s;
        int j=m+1;
        int k=s;
        while(i<=m&&j<=t)
        {
            if(p[i].v<=p[j].v)
            {
                temp[k++]=p[i++];
                temp[k-1].num+=(j-m-1);
            }
            else
            {
                temp[k++]=p[j++];
                temp[k-1].num+=(m-i+1);
            }
        }
        while(i<=m)
        {
            temp[k++]=p[i++];
            temp[k-1].num+=(j-m-1);
        }
        while(j<=t)
        {
            temp[k++]=p[j++];
            temp[k-1].num+=(m-i+1);
        }
    }
    void cop(int s,int t)
    {
        for(int i=s; i<=t; i++)
           p[i]=temp[i];
    }
    void megsort(int s,int t)
    {
        if(s<t)
        {
            int m=(s+t)/2;
            megsort(s,m);
            megsort(m+1,t);
            mer(s,m,t);
            cop(s,t);
        }
    }
    int main()
    {
        int n;
        while(~scanf("%d",&n))
        {
            for(int i=0; i<n; i++)
            {
                scanf("%lld",&p[i].v);
                p[i].num=0;
            }
            megsort(0,n-1);
            LL ans=0;
            for(int i=0; i<n; i++)
            {
                ans+=(p[i].num+1)*p[i].num/2LL;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }

     线段树+离散化

    #include<stdio.h>
    #include<iostream>
    #include<math.h>
    #include<string.h>
    #include<set>
    #include<map>
    #include<list>
    #include<math.h>
    #include<queue>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    #define INF 99999999
    #define me(a,x) memset(a,x,sizeof(a))
    int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
    int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
    
    LL getval()
    {
        LL ret(0);
        char c;
        while((c=getchar())==' '||c=='
    '||c=='
    ');
        ret=c-'0';
        while((c=getchar())!=' '&&c!='
    '&&c!='
    ')
            ret=ret*10+c-'0';
        return ret;
    }
    void out(int a)
    {
        if(a>9)
            out(a/10);
        putchar(a%10+'0');
    }
    
    #define max_v 1000005
    struct node
    {
        LL v,pos;
    }p[max_v];
    LL b[max_v];
    LL ans;
    struct node1
    {
        LL l,r;
        int w;
        int f;
    } tr[max_v*4];
    
    void build(LL k,LL ll,LL rr)
    {
        tr[k].l=ll,tr[k].r=rr;
        if(tr[k].l==tr[k].r)
        {
            tr[k].w=0;
            tr[k].f=0;
            return ;
        }
        LL m=(ll+rr)/2;
        build(k*2,ll,m);
        build(k*2+1,m+1,rr);
        tr[k].w=tr[k*2].w+tr[k*2+1].w;
        tr[k].f=0;
    }
    
    void down(LL k)
    {
        tr[k*2].f+=tr[k].f;
        tr[k*2+1].f+=tr[k].f;
        tr[k*2].w+=tr[k].f*(tr[k*2].r-tr[k*2].l+1);
        tr[k*2+1].w+=tr[k].f*(tr[k*2+1].r-tr[k*2+1].l+1);
        tr[k].f=0;
    }
    
    void ask_interval(LL k,LL a,LL b)//区间a b的和
    {
        if(tr[k].l>=a&&tr[k].r<=b)
        {
            ans+=tr[k].w;
            return ;
        }
        if(tr[k].f)
            down(k);
        LL m=(tr[k].l+tr[k].r)/2;
        if(a<=m)
            ask_interval(k*2,a,b);
        if(b>m)
            ask_interval(k*2+1,a,b);
    }
    
    void change_point(LL k,LL x,LL y)//第x个数加y
    {
        if(tr[k].l==tr[k].r)
        {
            tr[k].w+=y;
            return ;
        }
        if(tr[k].f)
            down(k);
        LL m=(tr[k].l+tr[k].r)/2;
        if(x<=m)
            change_point(k*2,x,y);
        else
            change_point(k*2+1,x,y);
        tr[k].w=tr[k*2].w+tr[k*2+1].w;
    }
    bool cmp(node x,node y)
    {
        if(x.v!=y.v)
            return x.v<y.v;
        else
            return x.pos<y.pos;
    }
    int main()
    {
        int n;
        while(~scanf("%d",&n))
        {
            for(int i=1;i<=n;i++)
            {
                cin>>p[i].v;
                p[i].pos=i;
            }
            sort(p+1,p+1+n,cmp);//离散化
            me(b,0);
            build(1,0,n);
            for(int i=1;i<=n;i++)
            {
                change_point(1,p[i].pos,1);
                ans=0;
                ask_interval(1,1,p[i].pos);
                b[i]+=i-ans;
            }
            build(1,0,n);
            for(int i=n;i>=1;i--)
            {
                change_point(1,p[i].pos,1);
                ans=0;
                ask_interval(1,0,p[i].pos-1);
                b[i]+=ans;
            }
            ans=0;
            for(int i=1;i<=n;i++)
            {
                ans+=(b[i]+1LL)*b[i]/2LL;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
     
  • 相关阅读:
    导航控制器生产,push,pop,root,index
    DNSserver内置笔记本
    解决“Dynamic Web Module 3.0 requires Java 1.6 or newer.”错误
    ssh配置连接
    在UITouch事件中画圆圈-iOS8 Swift基础教程
    iOS之UITableViewCell左右滑动效果
    iOS UIView非常用方法及属性详解
    IOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)
    UIColor,CGColor,CIColor三者的区别和联系
    iOS中正确的截屏姿势
  • 原文地址:https://www.cnblogs.com/yinbiao/p/10039823.html
Copyright © 2011-2022 走看看