【蓝桥杯】小朋友排队

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
/*
 * 题目最终归结到求每个数的逆序对的个数,逆序对的个数有多少个该数就要交换多少次
 * 方法:归并求逆序对的个数,求出每个数的逆序对的个数num
 * 步骤:先求小区间中的每个数的num,再回溯合并两个小区间为一个大区间并更新大区间中每个数的num
*/
struct Node
{
    long long int value, num;//num为与value相关的逆序对的个数总和(value前面比它大的数的个数+value后面比它小的数的个数)
};
void  Merge(vector<Node>&a, int s, int e, vector<Node>&temp)
{
    int mid = (s + e) / 2;
    int i = s, j = mid + 1;
    int k = s;//k从哪儿开始无所谓,我们这儿从s开始
    while (i <= mid&&j <= e)
    {
        //将数合并到temp中之前计算这个数的逆序对的个数(更新)
        if (a[i].value <= a[j].value)
            a[i].num += j - mid - 1, temp[k++] = a[i++];//[ a[mid+1],a[j-1] ]都小于a[i],个数为j-mid-1个
        else
            a[j].num += mid - i + 1, temp[k++] = a[j++];//[ a[i],a[mid] ]都大于a[j],个数为mid-i+1个
    }
    while (i <= mid)
        a[i].num += e - mid, temp[k++] = a[i++];//前半部分有剩余时,说明它比后半部分所有数都大,逆序对的个数增加,且都增加e-mid个
    for (i = s; i < k; i++)//写回原容器,为下次更新准备
        a[i] = temp[i];

}
/*
* 递归二分
*/
void MergeSort(vector<Node>&a, int s, int e, vector<Node>&temp)
{
    if (s < e)
    {
        int mid = (s + e) / 2;
        MergeSort(a, s, mid, temp);
        MergeSort(a, mid + 1, e, temp);
        Merge(a, s, e, temp);
    }
}
int main()
{
    int n;
    while (cin >> n)
    {
        vector<Node>a(n);
        vector<Node>temp(n);
        for (int i = 0; i < n; i++)
            cin >> a[i].value, a[i].num = 0;
        MergeSort(a, 0, n - 1, temp);
        long long int ans = 0;
        for (int i = 0; i < n; i++)
            ans += a[i].num*(a[i].num+1)/2;
        cout << ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值