小x同学在学习了通过归并排序求逆序对后对其产生了兴趣。在长度为n的序列a1,a2,….an中,对于一对数(ai,aj),当i < j 且 ai > aj是我们所说的普通的逆序对,那么i<j且ai>2×aj我们可以将其定义为“跳跃的逆序对”。小x想要知道在这个序列中有多少个“跳跃的逆序对”。但是小x能力有限,请你帮帮他解决这个问题。
输入格式:
第一行给定一个数N,表示该序列有N个数(1≤N≤200000),第二行为序列a1,a2...an(0≤ai≤10000000),由空格分开。
输出格式:
输出一个整数,为序列中“跳跃的逆序对”的个数。
输入样例:
10
0 9 8 7 6 5 4 3 2 1
输出样例:
16
此题在归并排序求逆序对的过程中增加一次模拟,只是模拟一次两个子数组排序,并不归并将两个子数组合并到一起,且第二个子数组需要新开并且赋值为原来的2倍,结果记得开long long。
代码参考:
#include <cstdio>
#include<iostream>
long long MergeSort(int s[], int left, int middle, int right)
{
int d[right+1];
for(int i=middle;i<=right;i++) d[i]=2*s[i];
int i = left, j = middle;
int b[right - left + 1];
int index = 0;
long long sum = 0;
int t = 0;
//
while (i < middle && j <= right){
if (s[i] > d[j])
{
j++;
t++;
}
//当j第一次到达right时,计算sum
if (s[i] <= d[j] || j == right + 1)
{
sum += t * (middle - i);
i++;
t = 0;
}
}
i=left;j=middle;
//
while (i < middle && j <= right)
{
if (s[i] > s[j]) b[index++] = s[j++];
if (s[i] <= s[j] ) b[index++] = s[i++];
}
while (i < middle)
b[index++] = s[i++];
while (j <= right)
b[index++] = s[j++];
index = 0;
for (int m = left; m <= right; m++)
s[m] = b[index++];
return sum ;//最后返回给k值
}
long long k = 0;
void Merge(int s[], int low, int high)
{
if (low < high)
{
int mid = (low + high) / 2;
Merge(s, low, mid);
Merge(s, mid + 1, high);
k += MergeSort(s, low, mid + 1, high);
}
}
int main()
{
int a[201000];
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
Merge(a, 0, n - 1);
printf("%lld\n", k);
return 0;
}