C/C++编程学习 - 第20周 ⑤ 逆序数
作者:互联网
题目链接
题目描述
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。
Input
第1行:N,N为序列的长度(n <= 50000) 第2 - N + 1行:序列中的元素(0 <= Ai <= 109)
Output
输出逆序数
Sample Input
4
2
4
3
1
Sample Output
4
思路
思路一:归并排序,思路看代码和注释吧。
C++代码:
#include<bits/stdc++.h>
using namespace std;
int g_nCount;
void mergearray(int a[], int first, int mid, int last, int temp[])
{
int i = first, j = mid + 1, m = mid, n = last, k = 0;
while(i <= m && j <= n) //a[i] 前面的数 a[j] 后面的数
{
if(a[i] < a[j]) temp[k++] = a[i++];
else
{
temp[k++] = a[j++]; //a[j]和前面每一个数都能组成逆序数对
g_nCount += m - i + 1;
}
}
while(i <= m)
temp[k++] = a[i++];
while(j <= n)
temp[k++] = a[j++];
for(i = 0; i < k; i++)
a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
if(first < last)
{
int mid = (first + last) / 2;
mergesort(a, first, mid, temp); //左边有序
mergesort(a, mid + 1, last, temp); //右边有序
mergearray(a, first, mid, last, temp); //再将二个有序数列合并
}
}
bool MergeSort(int a[], int n)
{
int *p = new int[n];
if(p == NULL) return false;
mergesort(a, 0, n - 1, p);
return true;
}
int a[50005];
int main()
{
int n;
while(cin >> n)
{
memset(a, 0, sizeof(a));
for(int i = 0; i < n; i++)
cin >> a[i];
g_nCount = 0;
MergeSort(a, n);
cout << g_nCount << endl;
}
return 0;
}
思路二:树状数组求逆序数。因为树状数组下标是从1开始的,所以用数组存的时候下标也要从1开始。然后给一个数组排序,再二分查找在排序后的数组中的位置。举个例子:2 4 3 1,排序后就是1 2 3 4,然后原数组中第一个元素2在第二个位置,4在第四个位置,然后找逆序就是该位置之后的元素个数,因为已经排好序了嘛,后面的元素肯定比前面的大,如果在该元素出现之前,已经有比它大的元素出现了,那么它就是一个逆序。
C++代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 50005;
int bit[maxn], n, a[maxn], b[maxn];
int lowbit(int x)
{
return (x & -x);
}
int sum(int i)
{
int s = 0;
while(i > 0)
{
s += bit[i];
i -= lowbit(i);
}
return s;
}
void add(int i, int x)
{
while(i <= n)
{
bit[i] += x;
i += lowbit(i);
}
}
void init()
{
memset(bit, 0, sizeof(bit));
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
}
int main()
{
while(scanf("%d", &n) == 1)
{
init();
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
b[i] = a[i];
}
sort(a + 1, a + n + 1);
int ans = 0;
for(int i = 1; i <= n; i++)
{
int pos = lower_bound(a + 1, a + n + 1, b[i]) - a;
add(pos, 1);
ans += sum(n) - sum(pos);
}
printf("%d\n", ans);
}
return 0;
}
标签:last,temp,int,mid,C++,20,first,序数 来源: https://blog.csdn.net/qq_44826711/article/details/113550463