AC日记——codevs 1688 求逆序对

1688 求逆序对

 

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 黄金 Gold
 
 
题目描述 Description

给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目

数据范围:N<=105。Ai<=105。时间限制为1s。

输入描述 Input Description
 

第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数。

输出描述 Output Description
 

所有逆序对总数.

 

样例输入 Sample Input
 

4

3

2

3

2

样例输出 Sample Output
 

3

数据范围及提示 Data Size & Hint
 
 
 
 
思路:
  经历了这么多的算法和结构
  唯独没碰到过归并排序
  今天整理考试题目
  猛然发现有一个题需要用归并排序来求逆序对
  所以
  现在拿个水题练练手
  因为没有接触过归并排序
  只知道归并排序要用递归来写
  所以自己摸索着写还是很吃力
  但我还是很顽强的写了出来
  归并排序
  首先定义变量l,r
  然后二分
  二分到l==r就return
  接下来就是排序
  mid=(l+r)/2
  把l到r分成两段
  以mid为分界线
  然后定义一个用于存储排序后的序列的数组
  定义两个记录两个区间排序情况的指针lik,rik
  if(a[lik]<=a[rik]) b[++now]=a[lik];
  就这样直到lik==mid,rik==r
  然后b数组已经赋值的部分排序到a数组相应的区间内
  然后在排序的同时记录逆序对的个数即可
 
  来,上代码:
#include<cstdio>

using namespace std;

int n,a[100001],b[100001];

unsigned long long int ans=0;

void nxd(int l,int r)
{
    if(l==r) return ;
    int mid=(l+r)/2;
    nxd(l,mid),nxd(mid+1,r);
    int lik=l,rik=mid+1,now=l-1;
    while(now<r)
    {
        if(lik<=mid&&rik<=r)
        {
            if(a[lik]<=a[rik])
            {
                b[++now]=a[lik++];
                ans+=rik-mid-1;
            }
            else b[++now]=a[rik++];
        }
        else
        {
            if(lik<=mid)
            {
                b[++now]=a[lik++];
                ans+=rik-mid-1;
            }
            else
            {
                b[++now]=a[rik++];
            }
        }
    }
    for(int i=l;i<=r;i++) a[i]=b[i];
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    nxd(1,n);
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6039100.html