题目大意:T代表T组样例,n个人以及k组为一个区域,然后接下来n个数表示n个人的位置,然后是两个置换:
- 每次只能交换相邻的两个人,每交换一次花费一秒。求出一个交换到要求的位置后花费的时间t1。
- 可以直接交换两个人的位置,花费的时间是两个人现在的位置差,可以同时交换,求交换到要求的位置后花费的时间t2。
求出t1比t2多花费的时间。
比如:
10 3
3 7 1 2 4 6 5 8 10 9
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)
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);
}
}