题意:给一个整数序列,求交换某两个数或者不交换能得到的最小的逆序数对数。
预处理每个位置到它前面的任意一个位置间比它大的数和小的数的个数,和到它后面的任意一个位置间比它大的数和小的数的个数。然后枚举任意两个位置就可以了。
#include<stdio.h>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
int qx[1003][1003],hx[1003][1003],qd[1003][1003],hd[1003][1003];
int a[1003],n;
void init()
{
int i,j;
for(i=0;i<=n-3;i++)
{
int tmpx=0,tmpd=0;
for(j=i+1;j<=n-2;j++)
{
if(a[j]<a[i])tmpx++;
qx[i][j+1]=tmpx;
if(a[j]>a[i])tmpd++;
qd[i][j+1]=tmpd;
}
}
for(i=n-1;i>=2;i--)
{
int tmpx=0,tmpd=0;
for(j=i-1;j>=1;j--)
{
if(a[j]<a[i])tmpx++;
hx[i][j-1]=tmpx;
if(a[j]>a[i])tmpd++;
hd[i][j-1]=tmpd;
}
}
}
int main()
{
int i,j,num;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)scanf("%d",&a[i]);
memset(qx,0,sizeof(qx));
memset(qd,0,sizeof(qd));
memset(hx,0,sizeof(hx));
memset(hd,0,sizeof(hd));
init();
num=0;
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(a[i]>a[j])num++;
}
}
int min=1000000;
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
int tmp=qd[i][j]-qx[i][j]+hx[j][i]-hd[j][i];
if(a[i]<a[j])tmp++;
if(a[i]>a[j])tmp--;
if(tmp<min)min=tmp;
}
}
if(min<0)num+=min;
printf("%d\n",num);
}
return 0;
}