逆序数例题

1,146 阅读3分钟

本弱鸡求逆序数只会用归并排序,好在目前做了四道题目,都可以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;
}