51Nod-1019-逆序数

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。
Input
第1行:N,N为序列的长度(n <= 50000)
第2 - N + 1行:序列中的元素(0 <= A[i] <= 10^9)
Output
输出逆序数
Input示例
4
2
4
3
1
Output示例
4

对于这道题,直接上来的思路就是进行选择对比(类似于选择排序,只不过忽略排序过程),但是只过了七成的数据,所以是不怎么好的,于是乎,了解到,可以用归并排序来做这道题,说到归并排序,最常用的就是用递归来实现,但是其中涉及到一个不断开数组的过程,很有可能会导致题爆掉,所以也是存在很大问题的,所以,想要实现这道题,初步判定需要归并排序,但是要使用非递归实现归并排序,也就是迭代实现。先上递归实现的代码(C):

#include <stdio.h>
#define _MAX 50001
long ans = 0;

//将有序的A[first..mid]和A[mid + 1..last]归并为有序的B[first..last]
void Merge(long *A, long *B, int first, int mid, int last)
{
    int i = first, j = mid + 1;
    int cur = first;
    while (i <= mid && j <= last)
    {
        if (A[i] <= A[j])
        {
            B[cur++] = A[i++];
        }
        else
        {
            B[cur++] = A[j++];
            ans += mid - i + 1; //核心代码,逆序数增加
        }
    }
    while (i <= mid)
    {
        B[cur++] = A[i++];
    }
    while (j <= last)
    {
        B[cur++] = A[j++];
    }
}

//将A[first..last]归并排序为B[first..last]
void MSort(long *A, long *B, int first, int last)
{
    int mid;
    long BT[_MAX];  //这里存在问题,当数据大时,递归层数多,容易爆掉。
    if (first == last)
    {
        B[first] = A[first];
    }
    else
    {
        mid = (first + last) / 2;
        MSort(A, BT, first, mid);
        MSort(A, BT, mid + 1, last);
        Merge(BT, B, first, mid, last);
    }
    return ;
}

int main(int argc, const char * argv[])
{
    int N, i = 1;
    long A[_MAX];
    scanf("%d", &N);
    for (; i <= N; i++)
    {
        scanf("%ld", &A[i]);
    }

    MSort(A, A, 1, N);

    printf("%ld\n", ans);
    return 0;
}

这个代码只过了七成的测试数据,不是完美的解题代码,所以接下来要给出真正可行的代码,如下(C):

#include <stdio.h>
#include <stdlib.h>
#define _MAX 50001
long ans = 0;

//将有序的A[first..mid]和A[mid + 1..last]归并为有序的B[first..last]
void Merge(long *A, long *B, int first, int mid, int last)
{
    int i = first, j = mid + 1;
    int cur = first;
    while (i <= mid && j <= last)
    {
        if (A[i] <= A[j])
        {
            B[cur++] = A[i++];
        }
        else
        {
            B[cur++] = A[j++];
            ans += mid - i + 1; //核心代码,逆序数增加
        }
    }
    while (i <= mid)
    {
        B[cur++] = A[i++];
    }
    while (j <= last)
    {
        B[cur++] = A[j++];
    }
}

//将A中相邻长度为s的子序列两两归并到B中
void MergePass(long *A, long *B, int k, int N)
{
    int i = 1, j;
    while (i <= N - 2 * k + 1)
    {
        Merge(A, B, i, i + k - 1, i + 2 * k - 1);
        i = i + 2 * k;
    }
    if (i < N - k + 1)
    {
        Merge(A, B, i, i + k - 1, N);
    }
    else
    {
        for (j = i; j <= N; j++)
        {
            B[j] = A[j];
        }
    }
}

void MSort(long *A, int N)
{
    long *B = (long *)malloc(sizeof(long) * N);
    int k = 1;
    while (k < N)
    {
        MergePass(A, B, k, N);
        k *= 2;
        MergePass(B, A, k, N);
        k *= 2;
    }
    return ;
}

int main(int argc, const char * argv[])
{
    int N, i = 1;
    long A[_MAX];
    scanf("%d", &N);
    for (; i <= N; i++)
    {
        scanf("%ld", &A[i]);
    }

    MSort(A, N);

    printf("%ld\n", ans);
    return 0;
}

理论上这种写法是可以AC的,但是不知道为啥,在三组测试数据中出现了运行时错误,一下子整个人都不自在了,25组测试数据,大的过去了,小的也过去了,偏偏是这中不溜的三组数据出现了问题,自己本地测试数据,结果均正确,搞得我不知所以了……

最后经过代码优化,只好写成这样才算是过去了-_-#

#include <stdio.h>
#define _MAX 50001
long ans = 0;

//将有序的A[first..mid]和A[mid + 1..last]归并为有序的B[first..last]
void Merge(long *A, long *B, int first, int mid, int last)
{
    int i = first, j = mid + 1;
    int cur = first;
    while (i <= mid && j <= last)
    {
        if (A[i] <= A[j])
        {
            B[cur++] = A[i++];
        }
        else
        {
            B[cur++] = A[j++];
            ans += mid - i + 1; //核心代码,逆序数增加
        }
    }
    while (i <= mid)
    {
        B[cur++] = A[i++];
    }
    while (j <= last)
    {
        B[cur++] = A[j++];
    }
}

//将A[first..last]归并排序为B[first..last]
void MSort(long *A, long *B, int first, int last)
{
    int mid;
    if (first < last)
    {
        mid = (first + last) / 2;
        MSort(B, A, first, mid);
        MSort(B, A, mid + 1, last);
        Merge(A, B, first, mid, last);
    }
    return ;
}

int main(int argc, const char * argv[])
{
    int N, i = 1;
    long A[_MAX];
    long B[_MAX];
    scanf("%d", &N);
    for (; i <= N; i++)
    {
        scanf("%ld", &A[i]);
        B[i] = A[i];
    }

    MSort(A, B, 1, N);

    printf("%ld\n", ans);
    return 0;
}

累死宝宝了!!!OVER!!!

全部评论

相关推荐

牛客771574427号:恭喜你,华杰
点赞 评论 收藏
分享
头像
11-21 11:39
四川大学 Java
是红鸢啊:忘了还没结束,还有字节的5k 违约金
点赞 评论 收藏
分享
小红书 后端开发 总包n+8w+期权
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务