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 }
  • 相关阅读:
    .net从后台返回js的提示框
    使用IntelliTrace的独立收集器帮助测试应用程序
    NuGet笔记
    使用.dmp+vs分析异常
    windbg笔记
    C# 删除文件、文件到到回收站及异常判断
    .Net利用反射调用DLL时,被调用DLL引用其它库问题
    C#中设置窗口圆角样式
    C# 中引用IHTMLDocument2
    c# 单实例运行
  • 原文地址:https://www.cnblogs.com/ISGuXing/p/8540559.html
Copyright © 2011-2022 走看看