OJ题目:click here~~
题目分析:给一个序列,选择两个数,交换这两个数的位置,使得交换后,序列的逆序数最少。给出交换后的逆序数。
先将序列中的数hash一下,是为了下面方便计算数的次数。
归并排序,求逆序数。
枚举所有可选的两个数a , b,计算这两个数之间,比a大的数,比a小的数,比b大的数,比b小的数。交换a , b 之后 ,逆序数 = 原来的逆序数 + 比a大的数 + 比b小的数 - 比a小的数 - 比b大的数 + a,b逆序数的变化。
AC_CODE
const int Max_N = 1002;
int x[Max_N] , h[Max_N] , sum ;
int dpless[Max_N][Max_N] ;//dp[i][j];到i处为止,比j小的数的个数
int dpbig[Max_N][Max_N] ;//dpbig[i][j]:到i处为止,比j大的数的个数
void Merg(int L , int R){
if(L == R) return ;
int M = (L + R)>>1;
Merg(L , M);
Merg(M + 1 , R);
for(int i = M + 1;i <= R;i++){
sum += (x + 1 + M) - upper_bound(x + L , x + 1 + M , x[i]);
}
sort(x + L , x + R + 1);
}
int main(){
int i , j , k , n;
while(scanf("%d",&n) != EOF){
for(i = 1;i <= n;i++){
scanf("%d",&x[i]);
h[i] = x[i];
}
//先hash一下
sort(x + 1 , x + 1 + n);//需要先排序
int len = unique(x + 1, x + 1 + n) - (x + 1);//不同的元素的个数
for(i = 1;i <= n;i++)
h[i] = lower_bound(x + 1 , x + 1 + len , h[i]) - x;
for(i = 1;i <= n;i++) x[i] = h[i];
sum = 0 ;
Merg(1 , n) ;//求原来序列的逆序数
if(!sum){
puts("0") ;
continue;
}
memset(dpless , 0 , sizeof(dpless));
memset(dpbig , 0 , sizeof(dpbig));
for(i = 1;i <= n;i++) x[i] = h[i];
for(i = 1;i <= n;i++){
for(j = 1;j <= len;j++)
dpless[i][j] = dpless[i - 1][j];
for(j = x[i] + 1;j <= len;j++)
dpless[i][j]++;
for(j = 1;j <= len;j++)
dpbig[i][j] = dpbig[i - 1][j];
for(j = 1;j < x[i];j++)
dpbig[i][j]++;
}
int ans = sum;
int a , b , aless , bless , abig , bbig ;
for(i = 1;i <= n;i++){
for(j = i + 1;j <= n;j++){
a = x[i];
b = x[j];
bless = dpless[j - 1][b] - dpless[i][b];
bbig = dpbig[j - 1][b] - dpbig[i][b];
abig = dpbig[j - 1][a] - dpbig[i][a];
aless = dpless[j - 1][a] - dpless[i][a];
int k = 0 ;
if(a < b) k = 1;
if(b < a) k = -1;
ans = min(ans , sum + bless + abig - aless - bbig + k);
}
}
cout << ans << endl;
}
}