题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
输入例子:
1,2,3,4,5,6,7,0
输出例子:
7
思路就是用归并排序,在排序的过程中记录当左下标所指的数大于右下标所指的数时,说明这右下标-m这段数都是逆序对,因此加上他们的个数。
值得注意的是,这里的归并排序合并的时候比较要从大往小进行比较,因为从小到大比较在累加时会有重复非常麻烦。
另外说说归并排序,很多算法中的归并排序在每轮归并的时候都开了n个数的数组,实际上最多只需要每轮(n+1)/2个数的数组就行了,另外在排序中还有复制的过程产生了O(n)的时间复杂度,实际上也完全不必要,完全可以在原数组中重排。 只需要将原数组中的前(n+1)/2个数复制到新建立的数组中,再用新建立的数组中和原数组下标在(n+1)/2后面的数进行比较,较小值从l开始存回原数组。
但是由于这种方法在归并的时候下标从小到大比较会比较方便,否则太繁琐了,因此这题并没有进行上述优化
int merge(vector<int> &a, int l, int m, int r)
{
vector<int> b,c;
int i = m, j =r,sum=0;
// for (i = m+1; i <= r; i++) b.push_back(a[i]);
// i = b.size()-1;
while (i>=l && j>=m+1)
{
if (a[i] < a[j]) b.push_back(a[j--]);
else
{
sum += j - m;
b.push_back(a[i--]);
if (sum >= 1000000007) sum = sum % 1000000007;
}
}
if (i<l || j<m+1)
{
while (i >=l)
{
b.push_back(a[i--]);
}
while (j >= m + 1) b.push_back(a[j--]);
}
for (i = 0; i < b.size(); i++) a[l + i] = b[b.size() - i - 1];
// cout << sum << endl;
return sum;
}
int merge_sort(vector<int> &a, int l, int r)
{
int result = 0;
int m = (l + r) / 2;
if (l >= r) return 0;
result += merge_sort(a, l, m) % 1000000007;
result += merge_sort(a, m + 1, r) % 1000000007;
result += merge(a, l, m, r) % 1000000007;
return result;
}