逆序數——冒泡排序的交換次數

 題目:

冒泡排序的交換次數

給定一個1~n的排列a,..,an-,求對這個數列進行冒泡排序所需要的交換次數(冒泡排序是每次找到滿足a>a+t的i,並交換a;和a++t,直到這樣的i不存在爲止的算法)。

限制條件

●1≤n≤100000

輸入


n=4,a={3,1,4,2}


輸出


3


分析:

冒泡排序的複雜度是O(n^2),所以無法通過模擬冒泡排序的過程來計算需要的交換次數。不過我們可以通過選取適當的數據結構來解決這個問題。

首先,所求的交換次數等價於滿足i<j, ai>aj的(i,j)數對的個數(這種數對的個數叫做逆序數)。而對於每一個j, 如果能夠快速求出滿足i,<j,ai>aj 的i的個數,那麼問題就能迎刃而解。我們構建一個值的範圍是1~n的BIT,按照j=0, 1, 2, . n-1的順序進行如下操作。

■把j-(BIT查 詢得到的前aj項的和)加到答案中

■把BIT中aj位置上的值加1

對於每一個j, (BIT查詢得到的前aj項的和)就是滿足i<j, ai>aj的I 的個數。因此把這個值從j中減去之後,得到的就是滿足i<j, ai>aj,的的個數。由於對於每一個j的復 雜度是0(logn),所以整個算法的複雜度是O(n log n)。

實現:

#include<iostream>
#include<vector>
using namespace std;
int n;
const int maxn = 1e9;
vector<int>bit(maxn);
void add(int i,int x) {
	while(i<maxn) {
		bit[i]+=x;
		i+=i&-i;
	}
}
int sum(int i) {
	int ans=0;
	while(i>0) {
		ans+=bit[i];
		i-=i&-i;
	}
	return ans;
}
int main() {
	cin>>n;
	int res=0;
	for(int i=0; i<n; ++i) {
		int t;
		cin>>t;
		res+=i-sum(t);
		add(t,1);
	}
	cout<<res;
	return 0;
}

 

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