归并排序求逆序数

归并排序是用分治法递归排序的方法:
先将未排序的序列分成两个序列, 两个序列(又分别是一个未排序序列, 递归排序)分别排序后复制到新的数组, 将两个新数组中的最小元素比较, 将较小的那个放入原数组中, 指针后移, 直到两个序列至少有一个为空, 将不为空的序列复制到原数组中。

步骤:以序列s为例

  1. 将尽量平均分成两个序列:序列1, 序列2
  2. 将序列1排序, 将序列2排序(递归)
  3. 将序列1、2合并

    排序过程中, 可以求出s的逆序数:在合并序列时,每向原数组中放入一个序列2中的最小元素, 逆序数就加上序列1中剩余元素的个数。

代码

#include<cstdio>

using namespace std;
const int Max =100010;

long long num;
int a[Max], b[Max];


void merge1(int s[], int first, int mid , int last)
{
    int i, j, k=first;;
    i=0;
    for(j=first; j<=mid; j++)
        a[i++] = s[j];//将序列1放到新数组a中
    int len1 = mid-first+1;
    i=0;
    for(j = mid+1; j<=last; j++)
        b[i++] = s[j];//将序列2放入新数组b中
    int len2 = last-mid;
    i=0;
    j=0;
    while(i<len1 && j<len2 && k<=last)
    {
        if(a[i] <=b[j])//将较小元素放到原数组
        {
            s[k++] = a[i++];
        }
        else
        {
            s[k++] = b[j++];
            num+=(len1-i);
        }
    }
    while(i<len1)s[k++] = a[i++];
    while(j<len2)s[k++] = b[j++];//将未提取完的元素提取完
}

void merge_sort(int s[], int first, int last)
{
    if(first<last)
    {
        int mid  = (first+last)/2;
        merge_sort(s, first, mid);
        merge_sort(s, mid+1, last);
        merge1(s, first, mid, last);
    }
}
int main()
{
    int n, s[Max];
    while(~scanf("%d", &n))
    {
        for(int i=0; i<n; i++)
        {
            scanf("%d", &s[i]);
        }
        num=0;
        merge_sort(s, 0, n-1);
        for(int i=0; i<n ;i++)
        {
            printf("%d ", s[i]);
            if((i+1)%10==0)printf("\n");
        }
        printf("\n%lld\n", num);
    }
    return 0;
}

HDU6318

Swaps and Inversions

Problem Description
Long long ago, there was an integer sequence a.
Tonyfang think this sequence is messy, so he will count the number of inversions in this sequence. Because he is angry, you will have to pay x yuan for every inversion in the sequence.
You don’t want to pay too much, so you can try to play some tricks before he sees this sequence. You can pay y yuan to swap any two adjacent elements.
What is the minimum amount of money you need to spend?
The definition of inversion in this problem is pair (i,j) which 1≤i

#include<cstdio>

using namespace std;
const int Max = 100010;
int a[Max], b[Max];
long long num;

void merge1(int s[], int first, int mid, int last)
{
     int i, j;
     i=0;
     for(j=first; j<=mid; j++)
         a[i++] = s[j];
     int len1 = mid-first+1;
     i=0;
     for(j = mid+1; j<=last; j++)
         b[i++] = s[j];
     int len2 = last-mid;
     i=0;
     j=0;
     int k=first;
     while(i<len1 && j<len2 && k<=last)
     {
         if(a[i] <= b[j])
         {
             s[k++] = a[i++];
         }
         else
         {
             s[k++] = b[j++];
             num += (len1-i);
         }
    }
    while(i<len1)s[k++] = a[i++];
    while(j<len2)s[k++] = b[j++];
}

void mergesort(int a[], int first , int last)
{
    if(first<last)
    {
        int mid = (first+last)/2;
        mergesort(a, first, mid);
        mergesort(a, mid+1, last);
        merge1(a, first, mid, last);
    }
}

int main()
{
    int n, x, y, a[100010];
    while(~scanf("%d%d%d", &n, &x, &y))
    {
        for(int i=0; i<n; i++)
        {
            scanf("%d", &a[i]);
        }
        num=0;
        mergesort(a, 0, n-1);
        if(x>y)
            printf("%lld\n", num*y);
        else
            printf("%lld\n", num*x);

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值