题意:给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列。
题目本质就是求逆序对了,简单介绍一下。逆序对是指在序列{a0,a1,a2...an}中,若ai<aj(i>j),则(ai,aj)上一对逆序对。而逆序数顾名思义就是序列中逆序对的个数。例如: 1 2 3是顺序,则逆序数是0;1 3 2中(2,3)满足逆序对的条件,所以逆序数只有1; 3 2 1中(1,2)(1,3)(2,3)满足逆序对,所以逆序是3。由定义不能想象,序列n的逆序数范围在[0,n*(n-1)/2],其中顺序时逆序数为 0,完全逆序时逆序数是n*(n-1)/2。
可以利用归并排序时计算逆序个数,时间复杂度是nlog2n,而空间复杂度2n。 利用归并求逆序是指在对子序列s1和s2在归并时,若s1[i]>s2[j](逆序状况),则逆序数加上s1.length-i,因为s1中i后面的数字对于s2[j]都是逆序的。具体看注释吧。
归并算法基本思路
设两个有序的子文件放在同一向量中相邻的位置上:R[low..m],R[m+1..high],先将它们合并到一个局部的暂存向量R1中,待合并完成后将R1复制回R[low..high]中。合并过程中,设置i,j和p三个指针,其初值分别指向这三个记录区的起始位置。合并时依次比较R[i]和R[j]的关键字,取关键字较小的记录复制到R1[p]中,然后将被复制记录的指针i或j加1,以及指向复制位置的指针p加1。
重复这一过程直至两个输入的子文件有一个已全部复制完毕(不妨称其为空),此时将另一非空的子文件中剩余记录依次复制到R1中即可。
PS : 网上还有线段树和树状数组过的。。 好空再好好学习下o(>﹏<)o。。
//POJ 2299 归并排序版 3896K 375MS
#include <stdio.h>
#include <string.h>
#define MID(X,Y) (((X)+(Y)) >> 1 )
#define N 500005
int a[N] ;
int temp[N] ;
double sum ; //注意结果的范围,int不够 max = N*(N-1)/2 > INT_MAX
void Merge ( int left , int mid , int right ) //并归
{
int index ;
index = 0 ;
int i , j ;
i = left ;
j = mid + 1 ;
while ( i <= mid && j <= right )
{
if ( a[i] <= a[j] )
{
temp[index++] = a[i++] ;
}
else
{
temp[index++] = a[j++] ;
sum += mid - i + 1 ; //注意:a[i]后面的数字对于a[j]都是逆序的
}
}
while ( i <= mid )
{
temp[index++] = a[i++] ;
}
while ( j <= right )
{
temp[index++] = a[j++] ;
}
for ( int k = 0 ; k < index ; k ++ ) //归并完成后将结果复制到原输入数组 */
{
a[left+k] = temp[k] ;
}
}
void Merge_Sort ( int left , int right ) //归并排序
{
if ( left < right )
{
int mid ;
mid = MID( left , right ) ;
Merge_Sort ( left , mid ) ;
Merge_Sort ( mid + 1 , right ) ;
Merge ( left , mid , right ) ;
}
}
int
main ( )
{
int n ;
while ( EOF != scanf ("%d" , &n ) )
{
if ( 0 == n )
{
break ;
}
for ( int i = 1 ; i <= n ; i ++ )
{
scanf ("%d" , & a[i] ) ;
}
sum = 0 ;
memset ( temp , 0 , sizeof ( temp ) ) ;
Merge_Sort ( 1 , n ) ;
printf ("%.0f\n" , sum ) ;
}
return 0 ;
}
线段树版:
//POJ 2299 线段树版 17996K 1141MS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX(A,B) ((A)>(B)?(A):(B))
#define MIN(A,B) ((A)<(B)?(A):(B))
#define MID(A,B) (((A)+(B))>>1)
#define L(X) ((X)<<1)
#define R(X) (((X)<<1)|1)
#define MAXN 500050
struct node
{
int left , right ;
int val ;
}tree[MAXN<<2];
struct ss
{
int val ;
int id ;
}a[MAXN];
int n ;
int resort[MAXN] ;
int
cmp ( const void *a , const void * b )
{
return -(((ss* )a)->val - ((ss*)b)->val) ;
}
void
Build_Tree ( int const l , int const r , int const root )
{
tree[root].left = l ;
tree[root].right = r ;
tree[root].val = 0 ;
if ( l < r )
{
int mid ;
mid = MID ( l , r ) ;
Build_Tree ( l , mid , L(root) ) ;
Build_Tree ( mid + 1 , r , R(root) ) ;
}
return ;
}
void
Modify ( int const l , int const r , int const root , int const val )
{
if ( l == tree[root].left && r == tree[root].right )
{
tree[root].val += val ;
}
else
{
int mid ;
mid = MID ( tree[root].left , tree[root].right ) ;
if ( r < mid )
{
Modify ( l , r , L(root) , val ) ;
}
else if ( l > mid )
{
Modify ( l , r , R(root) , val ) ;
}
else
{
Modify ( l , mid , L(root) , val ) ;
Modify ( mid + 1 , r , R(root) , val ) ;
}
}
return ;
}
int
Query ( int const x , int const root )
{
if ( tree[root].left == tree[root].right )
{
return tree[root].val ;
}
else
{
int mid ;
mid = MID ( tree[root].left , tree[root].right ) ;
if ( x <= mid )
{
return Query ( x , L(root) ) + tree[root].val ;
}
else
{
return Query ( x , R(root ) ) + tree[root].val ;
}
}
}
void
Discretization ( ) //离散化
{
int temp ;
temp = a[1].val ;
int p ;
p = 1 ;
for ( int i = 1 ; i <= n ; i ++ )
{
if ( a[i].val != temp )
{
a[i].val = ++p ;
temp = a[i].val ;
}
else
{
a[i].val = p ;
}
}
for ( int i = 1 ; i <= n ; i ++ )
{
resort[a[i].id] = a[i].val ;
}
return ;
}
int
main ( )
{
while ( EOF != scanf ("%d" , & n ) )
{
if ( !n )
{
break ;
}
Build_Tree ( 1 , MAXN , 1 ) ;
memset ( resort , 0 , sizeof ( resort ) ) ;
double sum ;
sum = 0 ;
for ( int i = 1 ; i <= n ; i ++ )
{
scanf ("%d" , & a[i].val ) ;
a[i].id = i ;
}
// sort(a+1,a+n+1,cmp);
qsort ( a + 1 , n , sizeof (a[0]) , cmp ) ;
Discretization ( ) ;
for ( int i = 1 ; i <= n ; i ++ )
{
sum += Query ( resort[i] , 1 ) ;
Modify ( resort[i] , MAXN , 1 , 1 ) ;
}
printf ("%.0f\n" , sum ) ;
}
return 0 ;
}