一开始以为是POJ 2299 的翻版,归并排序求逆序数
于是写出了以下的超时代码:
#include <stdio.h>
#define inf 1000000000
int n;
int a[10010];
int minnixu;
int nixu;
int num[10010];
int bak[10010];
void mergesort (int L, int R)
{
if (L >= R) return;
int mid = (L + R) / 2;
mergesort (L, mid);
mergesort (mid + 1, R);
for (int k = L; k <= R; ++k) bak[k] = num[k];
int i = L, j = mid + 1;
for (int k = L; k <= R; ++k)
if (i <= mid && (j > R || bak[i] < bak[j])) {
num[k] = bak[i];
i ++;
} else {
num[k] = bak[j];
nixu+=mid-i+1;
j ++;
}
}
int main()
{
while (scanf("%d",&n)!=EOF) {
minnixu=inf;
for (int i=0; i<n; i++) {
scanf("%d",a+i);
a[n+i]=a[i];
}
for (int i=0; i<n; i++) {
nixu=0;
for (int j=0; j< 2*n; j++)
num[j]=a[j];
mergesort(0+i,i+n-1);
if(nixu<minnixu)
minnixu=nixu;
}
printf("%d\n",minnixu);
}
}
后来一想。。。这么做的复杂度是 n^2 * log(n) ,的确让人无法接受,于是着手分析题意:
题目中的数列是 0到n-1的全排列
也就是说,每当我们做一次移位操作(将首元素 a 移到尾部)移位后数列的逆序数为移位前的逆序数 -a + (n-1-a) (-a是因为a之后有a个比a小的数,把a移到队尾,这些逆序将不存在;同理,+(n-1-a)是因为a之后有n-1-a个比a大的数,把a移到队尾,会形成相应的逆序)
于是利用此公式写出AC代码:
#include <stdio.h>
#define inf 1000000000
int n;
int a[10010];
int rs[10010]; //right small
int count;
int mincount;
int main()
{
while (scanf("%d",&n)!=EOF) {
count=0;
mincount=inf;
for (int i=0; i<n; i++) {
scanf("%d",a+i);
rs[i]=0;
}
for(int i=0; i<n; i++) {
for(int j=i+1;j<n; j++) {
if(a[j]<a[i])
rs[i]++;
}
}
for(int i=0;i<n;i++) {
count+=rs[i];
}
if(count < mincount) mincount=count;
for(int i=0;i<n;i++) {
count+=n-1-a[i];
count-=a[i];
if(count < mincount) mincount=count;
}
printf("%d\n",mincount);
}
}
浙公网安备 33010602011771号