归并排序
分治过程:
1 分成两半
2 分别进行归并排序(递归进行)
3 合并成一个有序表(归并思想)
#include <iostream>
using namespace std;
int cnt;
void merge(int *a, int l, int r, int *tmp) { //a数组在区间[l, r)内排序
if(r - l < 2) return; //如果只有两个元素 return;
int mid = l + ((r - l)/2);
int pos1 = l, pos2 = mid, pos_tmp = l;
merge(a, l, mid, tmp); //排序好左边
merge(a, mid, r, tmp); //排序好右边
while(pos1 < mid || pos2 < r) { //合并两个有序序列
if(pos2 >= r || (pos1 < mid && a[pos1] <= a[pos2])) tmp[pos_tmp++] = a[pos1++];
else tmp[pos_tmp++] = a[pos2++];
}
for(int i=l; i<r; i++) a[i] = tmp[i];
}
int a[100001], tmp[100001], n;
int main() {
cin >> n;
for(int i=1; i<=n; i++) cin >> a[i];
merge(a, 1, n+1, tmp);
cout << cnt << endl;
return 0;
}
逆序对问题
题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
输入输出格式
输入格式:第一行,一个数n,表示序列中有n个数。
第二行n个数,表示给定的序列。
给定序列中逆序对的数目。
输入输出样例
输入样例:
6 5 4 2 6 3 1
输出样例:
11
说明
对于50%的数据,n≤2500
对于100%的数据,n≤40000。
在归并的基础上稍作改动
在两个序列归并时,当右边的序列中的一个元素进入了tmp,
说明它比左边序列中还没进入tmp的每一个都小,
满足了a[i] < a[j].
因为右边序列元素的下标大于左边序列元素的下标,因此满足i > j.
【只要加上一条语句】while(pos1 < mid || pos2 < r) {
if(pos2 >= r || (pos1 < mid && a[pos1] <= a[pos2])) tmp[pos_tmp++] = a[pos1++];
else {
tmp[pos_tmp++] = a[pos2++];
cnt += mid - pos1; //此时左边一半的元素个数
}
}
while(pos1 < mid || pos2 < r) {
if(pos2 >= r || (pos1 < mid && a[pos1] <= a[pos2])) tmp[pos_tmp++] = a[pos1++];
else {
tmp[pos_tmp++] = a[pos2++];
cnt += mid - pos1; //此时左边一半的元素个数
}
}
#END_BLOG