逆序对是什么,对于一个序列a1,a2,a3.....an来说,,,满足a[ i ]>a[ j ]并且i < j的数对(i,j)就叫做逆序对。
一些性质:
1.对于一个逆序对为k的序列来说,要将这个序列排序成为完全没有逆序对的序列,即任意两个元素之间都满足比较关系,则至少需要交换相邻序对的次数为序列的逆序对数k,并且一定存在一个k次交换相邻元素的算法。
2.对于一个元素全部相同的序列来说,选择其中的一个逆序对进行交换,总的逆序对个数变化将会减少奇数次。因为我们可以任选一个序列中的逆序对。 .........ai.....aj...... 对于ai 和 aj 分别左边和右边的数来说,他们对整个逆序对的贡献将会不变。只用考虑在ai和aj中间的数,分为三类,完全大于max(ai,aj)x个 、完全小于min(ai,aj)y个、处于ai,aj之间的数z个。中间的数贡献会减少2z个贡献(分析一下就知道),加上ai,aj本身减少了1个贡献,总的逆序对数会减少1+2z个。
3.对于一串0-n的数字组组成的序列,最前面的数字 a[0]的贡献是a[n],最后面一个数字a[n]的贡献是n-a[n].
算法实现:
归并排序:
int n;
int a[maxn];
int temp[maxn];
ll ans;
void msort(int l,int r,int *a,int *temp) //mergrsort();
{
if(l==r)
return;
int mid=(l+r)/2;
msort(l,mid,a,temp);
msort(mid+1,r,a,temp);
int i=l,j=mid+1; //指向a左边和右边的指针
int k=l; //指向temp位置的指针
while(i<=mid&&j<=r) //两两比较,知道其中一个到达末端
{
if(a[i]<=a[j])
temp[k++]=a[i++];
else
{
temp[k++]=a[j++];
ans=ans+(mid-i+1);
}
}
while(i<=mid) //将剩下的放入temp中
temp[k++]=a[i++];
while(j<=r)
temp[k++]=a[j++];
for(i=l; i<=r; i++) //temp反复制进入a
a[i]=temp[i];
}
//调用
ll getMergeSort(int l,int r,int *a)
{
ans=0;
msort(l,r,a,temp);
return ans;
}
线段树:
八数码等方格移动问题