首页 > 代码库 > UVALive 6604 Airport Sort 【归并排序】【逆序数】

UVALive 6604 Airport Sort 【归并排序】【逆序数】

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4615

题目大意:T代表T组样例,n个人以及k组为一个区域,然后接下来n个数表示n个人的位置,然后是两个置换:

  1. 每次只能交换相邻的两个人,每交换一次花费一秒。求出一个交换到要求的位置后花费的时间t1。
  2. 可以直接交换两个人的位置,花费的时间是两个人现在的位置差,可以同时交换,求交换到要求的位置后花费的时间t2。
求出t1比t2多花费的时间。
比如:
10 3
3 7 1 2 4 6 5 8 10 9
这一组样例:
第一个置换:
I. swap   7 with 1 ? 3 1 7 2 4 6 5 8 10 9
II. swap  7 with 2 ? 3 1 2 7 4 6 5 8 10 9
III. swap 7 with 4 ? 3 1 2 4 7 6 5 8 10 9
IV. swap 7 with 6 ? 3 1 2 4 6 7 5 8 10 9
V. swap  7 with 5 ? 3 1 2 4 6 5 7 8 10 9
VI. swap 10 with 9 ? 3 1 2 4 6 5 7 8 9 10 (now everyone is where they are supposed to be)
一共花费了6秒
第二个置换:
直接交换位置,那么花的时间最多的就是:
3 7 1     2 4 6     5 8 10    9
5秒。
所以第二个置换比第一个置换少了1秒。

比赛的时候遇到这个题目,第二个置换可以用贪心直接搞出来,但是第一个不会搞。
后来看题解说是归并排序可以搞出来。发现原来归并排序求逆序数竟然能这么用..........  
a[i] =( a[i] -1 ) / k + 1  将 a[i] 进行了一定变换,然后可以求逆序数了。

//从归并排序到数列的逆序数对
#include <stdio.h>
#include <iostream>
using namespace std;

int g_nCount = 0;
void mergearray(int a[], int first, int mid, int last, int temp[])
{
    int i = first, j = mid + 1;
    int m = mid,   n = last;
    int k = 0;

    while (i <= m && j <= n) //a[i] 前面的数  a[j] 后面的数
    {
        if (a[i] <= a[j])temp[k++] = a[i++];
        else{
            temp[k++] = a[j++];//a[j]和前面每一个数都能组成逆序数对
            g_nCount += m - i + 1;
        }
    }
    while (i <= m) temp[k++] = a[i++];
    while (j <= n) temp[k++] = a[j++];
    for (i = 0; i < k; i++) a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
    if (first < last)
    {
        int mid = (first + last) / 2;
        mergesort(a, first, mid, temp);    //左边有序
        mergesort(a, mid + 1, last, temp); //右边有序
        mergearray(a, first, mid, last, temp); //再将二个有序数列合并
    }
}

bool MergeSort(int a[], int n)
{
    int *p = new int[n];
    if (p == NULL)
        return false;
    mergesort(a, 0, n - 1, p);
    delete[] p;
    return true;
}

int main ()
{
    int  CASE,T,k,a[1005];
    scanf("%d",&CASE);
    for(int cas = 1; cas<=CASE; cas++){
        scanf("%d %d",&T,&k);
        g_nCount = 0;
        int count2=0;
        for(int i = 0; i < T; i++){
            scanf("%d",&a[i]),a[i]=(a[i]-1)/k + 1;
            int m = i / k + 1;
            if(m>a[i])
                count2=max(count2,i+1-(k*a[i]+1));
            
            else if(m<a[i])
                count2=max(count2,k*(a[i]-1)+1-(i+1));
            
        }
        MergeSort(a,T);
        printf("Case %d: %d\n",cas,g_nCount-count2);
    }
}








UVALive 6604 Airport Sort 【归并排序】【逆序数】