本弱鸡求逆序数只会用归并排序,好在目前做了四道题目,都可以AC(偷笑)。
关于归并排序和如何用归并排序求逆序数,可以看我写的另一篇文章。
例一
本校的oj,需要连接本校校园网或者挂本校的vpn才能打开,所以下附题面。
题目内容
Description
You have an array which has N numbers. Please find the number of different collocation for three number Ai, Aj, Ak, which satisfy that Ai < Aj > Ak and i < j < k.
Input
There are several test cases.
For each case, the first line is the number N (3 ≤ N ≤ 50000).
The second line contains N integers representing the array, A1, A2, ... An (1 ≤ Ai ≤ 32768).
Output
For each case, output the number of different collocation.
Sample Input
4
1 2 3 1
5
1 2 3 4 1
Sample Output
3
6
简单理解
求一下每个数字前面和后面各有多少个比自己小的,然后相乘加到sum上就行了。
这里有一个小小的问题转化:
首先,排序之后我可以知道比我小的数字的个数。
所以,如果已经知道前面有多少个比我小,相减之后就是后面比我小的数字的个数。
一个元素的逆序数表示的是在这个数字前面比自己大的数字个数。
而我们要的是在前面比自己小的数字个数,所以只要把从小到大排序变为从大到小就OK了。
AC代码
#include <iostream>
using namespace std;
typedef long long ll;
const int maxnum=100000;
struct node{
int val;
int inf;
};
node a[maxnum];
node tem[maxnum];
int order[maxnum];
/*合并两个闭区间[l,m]和[m+1,r]*/
void SubMergeSort(int l, int m, int r)
{
int i = l;
int j = m + 1;
int k = l;///注意这里是l不是1
while(i <= m&&j <= r)
{
if(a[i].val < a[j].val)
{
a[j].inf += m-i+1;
tem[k++] = a[j++];
}
else
tem[k++] = a[i++];
}
while(i <= m) tem[k++] = a[i++];
while(j <= r) tem[k++] = a[j++];
/*从tem复制到a*/
for(int i = l;i <= r; i++) a[i] = tem[i];
}
void MergeSort(int l, int r)
{
if(l < r)
{
int m = (l + r)/2;///不懂不要瞎改
MergeSort(l, m);
MergeSort(m+1, r);
SubMergeSort(l, m, r);
}
}
int main()
{
int n;
while(cin >> n)
{
for(int i = 0; i < n; i++)
{
cin >> a[i].val;
a[i].inf = 0;
}
MergeSort(0, n-1);
int temp = a[0].val;
for(int i = 0; i < n; i++)
{
order[a[i].val] = n - (i+1);
}
ll res = 0;
for(int i=0;i<n;i++)
{
res += (ll)(order[a[i].val] - a[i].inf)*(ll)a[i].inf;
}
cout << res << endl;
}
return 0;
}
例二
HDU4911 Inversion
#include <iostream>
#define ll long long
using namespace std;
const int maxnum=100000;
int a[maxnum];
int tem[maxnum];
ll ans;
/*合并两个闭区间[l,m]和[m+1,r]*/
void SubMergeSort(int l,int m,int r)
{
int i = l;
int j = m+1;
int k = l;///注意这里是l不是1
while(i<=m&&j<=r)
{
if(a[i]>a[j])
{
ans += m-i+1;///只计算总逆序数(相等的不算)
tem[k++] = a[j++];
}
else
tem[k++] = a[i++];
}
while(i<=m) tem[k++] = a[i++];
while(j<=r) tem[k++] = a[j++];
/*从tem复制到a*/
for(int i=l;i<=r;i++) a[i] = tem[i];
}
void MergeSort(int l,int r)
{
if(l<r)
{
int m = (l+r)/2;///不懂不要瞎改
MergeSort(l,m);
MergeSort(m+1,r);
SubMergeSort(l,m,r);
}
}
int main()
{
int n, k;
while(cin >> n >> k)
{
for(int i=0;i<n;i++)
{
cin>>a[i];
}
ans = 0;
MergeSort(0,n-1);
cout << max((ll)0, ans-(ll)k)<<endl;///题目太卑鄙了,卡longlong
}
return 0;
}