逆序对问题

逆序对是什么,对于一个序列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;
}



 

线段树:

 

八数码等方格移动问题

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章