zoukankan      html  css  js  c++  java
  • 蓝桥杯-小朋友排队

    问题描述
      n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。

      每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。

      如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。

      请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。

      如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
    输入格式
      输入的第一行包含一个整数n,表示小朋友的个数。
      第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。
    输出格式
      输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
    样例输入
    3
    3 2 1
    样例输出
    9
    样例说明
      首先交换身高为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。
    解题思路:
    1、我先用了冒泡一下,果断超时。
    2、正解:求解逆序对。
    方法:树状数组求解逆序对。因为树状数组在求解逆序上有着非常方便的功效。
    统计每个小朋友前后的逆序数。然后就可以计算出该小朋友最后会有多少不满意度,最后将所有小朋友的不满意度加一起就是答案。
    这里需要注意的是1、可能有小朋友的身高一样。2、身高可能为0!!!只需要输入的时候加一就行了。
    唯一麻烦处理的就是身高一样的情况。
    我先采用的是输入的时候统计有哪些身高有多少相同的小朋友。先算前逆序数,然后可以用公式算出来后逆序数有多少个。
    后面用了网上的一种好的方法,统计两次前逆序数,只不过第二次反着算!
    (ps:用long long)
    方法一:
    #include<iostream>
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll lowbit(ll x){
        return x&(-x);
    }
    struct Node{
        ll heigh,qian,times;
    } a[100600];
    ll flag[1000050];
    void add(ll x,ll  getsum[]){
        while(x<1000050){
            getsum[x]++;
            x+=lowbit(x);
        }
    }
    ll left_query(Node a,ll num,ll  getsum[]){
         ll x=a.heigh;
         ll ans=0;
         while(x!=0){
            ans+=getsum[x];  //统计当前序列比x小的个数
            x-=lowbit(x);
         }
         return num-ans;
    }
    ll right_query(Node a,ll num,ll sum,ll getsum[]){
        ll x=a.heigh;
        ll ans=0;
        while(x!=0){
            ans+=getsum[x];
            x-=lowbit(x);
        }
        ll m=(sum-num)-(sum-ans-a.times)-(flag[a.heigh]-a.qian);
        return m;
    }
    ll getsum[1000050];
    int main(){
        ll n;
        cin>>n;
        for(ll i=1;i<=n;i++){
            scanf("%d",&a[i].heigh);
            a[i].heigh++;
            flag[a[i].heigh]++; //标记身高
            a[i].qian=flag[a[i].heigh]; //统计前面有多少个与他相同身高的数量
            a[i].times=0; //移动次数初始化
            add(a[i].heigh,getsum); //插入序列
            a[i].times=left_query(a[i],i,getsum); //左查询
        }
        ll ans=0;
        for(ll i=1;i<=n;i++){
            a[i].times+=right_query(a[i],i,n,getsum); //右查询
            ans+=((1+a[i].times)*a[i].times)/2;
        }
        cout<<ans<<endl;
        return 0;
    }

    方法二:

     1 #include<iostream>
     2 #include<bits/stdc++.h>
     3 #define ll long long
     4 using namespace std;
     5 ll lowbit(ll x){
     6     return x&-x;
     7 }
     8 void add(ll x,ll getsum[]){
     9     while(x<1000000){
    10         getsum[x]++;
    11         x+=lowbit(x);
    12     }
    13 }
    14 ll left_query(ll x,ll i,ll getsum[]){
    15     ll ans=0;
    16     while(x!=0){
    17         ans+=getsum[x];
    18         x-=lowbit(x);
    19     }
    20     return i-ans;
    21 }
    22 ll right_query(ll x,ll i,ll getsum[]){
    23     ll ans=0;
    24     x--;
    25     while(x!=0){
    26         ans+=getsum[x];
    27         x-=lowbit(x);
    28     }
    29     return ans;
    30 }
    31 ll a[100500];
    32 ll b[100500];
    33 ll times[100500];
    34 ll getsum[1050000];
    35 int main(){
    36     ll n;
    37     cin>>n;
    38     ll k=n;
    39     for(ll i=1;i<=n;i++){
    40         scanf("%d",a+i);
    41         b[k--]=++a[i];
    42         add(a[i]+1,getsum);
    43         times[i]=left_query(a[i]+1,i,getsum);
    44     }
    45     k=n;
    46     memset(getsum,0,sizeof(getsum));
    47     for(ll i=1;i<=n;i++){
    48         add(b[i]+1,getsum);
    49         times[k--]+=right_query(b[i]+1,i,getsum);
    50     }
    51     ll sum=0;
    52     for(ll i=1;i<=n;i++){
    53         sum+=((1+times[i])*times[i])/2;
    54     }
    55     cout<<sum<<endl;
    56     return 0;
    57 }
  • 相关阅读:
    LeetCode 842. Split Array into Fibonacci Sequence
    LeetCode 1087. Brace Expansion
    LeetCode 1219. Path with Maximum Gold
    LeetCode 1079. Letter Tile Possibilities
    LeetCode 1049. Last Stone Weight II
    LeetCode 1046. Last Stone Weight
    LeetCode 1139. Largest 1-Bordered Square
    LeetCode 764. Largest Plus Sign
    LeetCode 1105. Filling Bookcase Shelves
    LeetCode 1027. Longest Arithmetic Sequence
  • 原文地址:https://www.cnblogs.com/ISGuXing/p/8540559.html
Copyright © 2011-2022 走看看