逆序對是什麼,對於一個序列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;
}
線段樹:
八數碼等方格移動問題