DHUOJ Frosh Week

Frosh Week

时间限制: 1S类别: 枚举和贪心->中等

问题描述 :

During Frosh Week, students play various fun games to get to know each other and compete against other teams. In one such game, all the frosh on a team stand in a line, and are then asked to arrange themselves according to some criterion, such as their height, their birth date, or their student number. This rearrangement of the line must be accomplished only by successively swapping pairs of consecutive students. The team that finishes fastest wins. Thus, in order to win, you would like to minimize the number of swaps required.

输入说明 :

The first line of input contains one positive integer n, the number of students on the team, which will be no more than one million. The following n lines each contain one integer, the student number of each student on the team. No student number will appear more than once.

输出说明 :

Output a line containing the minimum number of swaps required to arrange the students in increasing order by student number.


输入范例 :

20
824999217
22573102
984397395
215416235
247826578
910725073
941794862
173672226
419559552
719826673
141666075
82167875
444979293
319136227
351013707
904455923
398197417
94379523
759276975
50151619

输出范例 :

108


思路:

本质上即求数组的逆序对个数,第一反应想到冒泡,但是冒泡复杂度O(n^2),再看这题数据量100万,显然会超时

那可以想到,将大问题分解成小问题,求出小块的逆序对数再相加,即可算出总块的逆序对,用归并排序可以实现,时间复杂度为O(nlogn)


代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<iomanip>
#include<vector>
#include<string>
#include<set>
#include<utility>
using namespace std;
//求逆序数
int n;

int mergeSort(int a[], int l, int r) {//即求区间[l,r]之间有多少个逆序对
    //[l,r]之间的逆序对可分为 1.[l,mid]的逆序对 2.[mid+1,r]的逆序对 3.横跨两个区间的逆序对
    int mid = (l + r) / 2;
    if (l >= r)
        return 0;//区间中包含一个或者没有元素,显然逆序对为0

    int* tmp = new int[n + 5];
    int pos = l;
    int cnt = mergeSort(a, l, mid) + mergeSort(a, mid + 1, r);//求出1. 2. 的逆序对数
    
    //求3. 的逆序对数
    int i = l, j = mid + 1;
    while (i <= mid && j <= r) {
        if (a[i] <= a[j]) {
            tmp[pos] = a[i];
            i++;
            pos++;
        }
        else {
            tmp[pos] = a[j];
            j++;
            pos++;
            cnt += (mid - i + 1);
        }
    }

    //剩下元素加入
    for (i; i <= mid; i++) {
        tmp[pos] = a[i];
        pos++;
    }
    for (j; j <= r; j++) {
        tmp[pos] = a[j];
        pos++;
    }

    //修改为(部分)排序后的数组
    for (int m = l; m <= r; m++)
        a[m] = tmp[m];

    return cnt;
}

int main()
{

    cin >> n;
    int* a = new int[n + 5];
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    int res = mergeSort(a, 0, n - 1);
    cout << res << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值