蓝桥杯历年试题 小朋友排队

问题描述
  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。
 
思路:
逆序数的变形,不仅要求逆序数的对数,还要把对数明确到每一个单位,在求的过程中要注意排除相等的情况(如果有更方便的排除法麻烦留个言,感觉自己写的判断有点麻烦),用树状数组求也需要判断。
使用了归并排序求逆序数的方法,把模板改了一下。
#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#include <map>
#include <algorithm>
#define LL long long int
#define N 100005
using namespace std;
int cmp(int a,int b)
{
    if(a==b) return 0;
    return a<b?-1:1;
}
struct node
{
    int num;
    int ang;

};
LL ans[N];
void MergeArr(node num[], int left, int mid, int right)
{
    node AL[N], AR[N];
    int lenl=mid-left+1,lenr=right-mid;
    for (int i = 0;i < lenl;i++)
        AL[i] = num[left + i];
    for (int i = 0;i < lenr;i++)
        AR[i] = num[mid + 1 + i];
    int j = 0, k = 0,pos=left;
    int tempNum=-1,tempCnt=0;
    while (j < lenl&&k < lenr)
    {
        int fix=cmp(AL[j].num, AR[k].num);
        if (fix<=0)
        {
            num[pos++] = AL[j++],num[pos-1].ang+=k;
            if(num[pos-1].num==tempNum)
                num[pos-1].ang-=tempCnt;
        }
        //else if(fix==-1) num[pos++] = AL[j++];
        else
            num[pos++] = AR[k++],num[pos-1].ang+=mid-(left+j)+1;//关键步骤
        if(fix>0)
        {
            if(num[pos-1].num==tempNum)
                tempCnt++;
            else
                tempNum=num[pos-1].num,tempCnt=1;
        }

    }
    while (j < lenl)
    {
        num[pos++] = AL[j++];
        num[pos-1].ang+=k;
        if(num[pos-1].num==tempNum)
            num[pos-1].ang-=tempCnt;
    }
    while (k < lenr)
        num[pos++] = AR[k++];
}
void MergeSort(node num[], int left, int right)
{
    if (left < right)
    {
        int mid = (right + left) / 2;
        MergeSort(num, left, mid);
        MergeSort(num, mid+1, right);
        MergeArr(num, left, mid, right);
    }
}
LL mat(LL num)
{
    return num*(num+1)/2;
}
node num[N];
int n;
int main()
{
    cin.sync_with_stdio(false);
    while(cin>>n)
    {
        LL fuck=0;
        for(int i=0;i<n;i++)
            cin>>num[i].num,num[i].ang=0;
        MergeSort(num,0,n-1);
        for(int i=0;i<n;i++)
            fuck+=mat(num[i].ang);

        cout<<fuck<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LukeStepByStep/p/6387507.html