分治(Divide and Conquer)的核心思想很简单,就是把一个大问题拆解成几个规模更小的子问题,分别解决后再合并结果。这种策略在算法竞赛和工程实践中都非常常见。
1. 逆序对
题目参考:P1908 逆序对 - 洛谷
核心思路
分治是解决逆序对问题最经典的做法。我们把原数组从中间 mid 一分为二,答案包含以下三种情况:
- 左边数组内部的逆序对个数 a
- 右边数组内部的逆序对个数 b
- 左数组选一个数,右数组选一个数,构成逆序对的总个数 c
那么总个数 ret = a + b + c。同理,我们继续划分,把左数组再一分为二讨论,右数组一分为二讨论,直到数组无法划分(只有一个数)。
当左右两边的子问题答案得到时,要处理的是一左一右的情况。这个时候我们可以利用排序后的特性来求解。例如排完序得到:1 5 6 / 2 4 8。利用双指针求解:定义 cur1 从左往右遍历左数组,cur2 从左往右遍历右数组,cnt 为构成逆序对的个数。
当 v[cur1] > v[cur2] 时,说明 cur1 及其之后的所有元素都大于 v[cur2](因为单调递增),所以 cnt += (mid - cur1 + 1),然后 cur2++。否则 cur1++。
代码实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> v;
long long merge(int left, int right) {
if (left >= right) return 0;
int mid = (left + right) / 2;
long long ret = 0;
// 递归处理左右两边
ret += merge(left, mid);
ret += merge(mid + 1, right);
(v.() + left, v.() + mid + );
(v.() + mid + , v.() + right + );
cur1 = left;
cur2 = mid + ;
(cur1 <= mid && cur2 <= right) {
(v[cur1] <= v[cur2]) {
cur1++;
} {
ret += mid - cur1 + ;
cur2++;
}
}
ret;
}
{
n;
cin >> n;
( i = ; i < n; i++) {
num;
cin >> num;
v.(num);
}
cout << (, v.() - ) << endl;
;
}


