逆序数的概念:对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。

解决思路:

HDU-1394

1、线段树:通过保存区间内数的出现次数,每次插入一个数前把比它小(大)的区间内的总数累加。

 //求逆序数 线段树法
//原理,因为输入是依次输入的,所以每次输入一个数,只要查找比这个数小数的个数并累加就行了。
//顺序查找的复杂度是O(n),很容易想到用线段树保存每个数的出现次数,每次输入在比他小(大)的区间中查找总数就行了
#include <iostream>
#define N 5010
using namespace std;
int tree[N<<];//线段树保存了每个区间内数字出现总数
void CreatTree(int node,int l,int r)
{
if(l==r)
{
tree[node]=;
return ;
}
int mid=(l+r)>>;
CreatTree(node<<, l, mid);
CreatTree(node<<|, mid+, r);
tree[node]=tree[node<<]+tree[node<<|];
}
void Insert(int node,int num,int l,int r)
{
if(l==num&&r==l)
{
tree[node]++;
return ;
}
int mid=(l+r)>>;
if(num<=mid)
Insert(node<<, num, l, mid);
else
Insert(node<<|, num, mid+, r);
tree[node]=tree[node<<]+tree[node<<|];
}
int Query(int node,int ql,int qr,int l,int r)
{
if(qr<ql)
return ;
if(ql<=l&&r<=qr)
return tree[node];
int mid=(l+r)>>;
int rec=;
if(ql<=mid)
rec+=Query(node<<, ql, qr, l, mid);
if(qr>mid)
rec+=Query(node<<|, ql, qr, mid+, r);
return rec;
}
int main(int argc, const char * argv[]) {
int n;
while(cin>>n)
{
int ans=,temp;
int num[N];
CreatTree(, , n-);
for(int i=;i<n;i++)
{
cin>>temp;
num[i]=temp;
Insert(, temp, , n-);
ans+=Query(, temp+,n-, , n-);
}
int sum=ans;
for(int i=;i<n;i++)
{
ans=ans-num[i]+n-num[i]-;
if(ans<sum)
sum=ans;
}
cout<<sum<<endl;
}
return ;
}

2、归并排序:归并排序过程中,如果左序列的第j个值大于有序列第k个值,那么j~lenl的值都大于k,所以每次ans+=

id-(left+j)+1。完成整个归并排序,就可以统计所有逆序数对的数量。

 //求逆序数 归并排序法
//在归并排序过程中,每次对左右两个有序数列排序时,如果左边序列的第j个值大于右边序列k个值
//那么说明左边序列的j~lenl个值都大于第k个值,所以把其加到ans中
#include <iostream>
#define N 5010
using namespace std;
bool cmp(int a,int b)
{
return a<=b;
}
int ans;
void MergeArr(int num[], int left, int mid, int right)
{
int AL[N], AR[N],lenl=mid-left+,lenr=right-mid;
for (int i = ;i < lenl;i++)
AL[i] = num[left + i];
for (int i = ;i < lenr;i++)
AR[i] = num[mid + + i];
int j = , k = ,pos=left;
while (j < lenl&&k < lenr)
{
if (cmp(AL[j], AR[k]))
num[pos++] = AL[j++];
else
num[pos++] = AR[k++],ans+=mid-(left+j)+;//关键步骤
}
while (j < lenl)
num[pos++] = AL[j++];
while (k < lenr)
num[pos++] = AR[k++];
}
void MergeSort(int num[], int left, int right)
{
if (left < right)
{
int mid = (right + left) / ;
MergeSort(num, left, mid);
MergeSort(num, mid+, right);
MergeArr(num, left, mid, right);
}
}
int main() {
int n;
while(cin>>n)
{
ans=;
int num[N],temp[N];
for(int i=;i<n;i++)
cin>>num[i],temp[i]=num[i];
MergeSort(temp, , n-);
int sum=ans;
for(int i=;i<n;i++)
{
ans=ans-num[i]+n-num[i]-;
if(ans<sum)
sum=ans;
}
cout<<sum<<endl;
}
return ;
}

求逆序数的方法--线段树法&归并排序法的更多相关文章

  1. HDU 1394.Minimum Inversion Number-最小逆序数-完全版线段树(单点增减、区间求和)

    HDU1394.Minimum Inversion Number 这个题求最小逆序数,先建一个空的树,然后每输入一个值,就先查询一下,查询之后,更新线段树,然后遍历一遍,每次将第一个数放到最后之后,减 ...

  2. codevs1688 求逆序对(权值线段树)

    1688 求逆序对  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 给定一个序列a1,a2,…, ...

  3. hdu 1394 Minimum Inversion Number(线段树之 单点更新求逆序数)

    Minimum Inversion Number                                                                           T ...

  4. Ultra-QuickSort (求逆序数+离散化处理)、Cows、Stars【树状数组】

    一.Ultra-QuickSort(树状数组求逆序数) 题目链接(点击) Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total ...

  5. poj 3067 Japan(树状数组求逆序数)

    链接:http://poj.org/problem?id=3067 题意:左边有n个城市,右边有m个城市,建k条道路,问有这k条道路中有多少个交点. 分析:将城市按x和y从小到大排序,对于每条道路,求 ...

  6. hiho一下 第三十九周 归并排序求逆序数

    题目链接:http://hihocoder.com/contest/hiho39/problem/1 ,归并排序求逆序数. 其实这道题也是可以用树状数组来做的,不过数据都比较大,所以要离散化预处理一下 ...

  7. poj 2299 Ultra-QuickSort :归并排序求逆序数

    点击打开链接 Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 34676   Accepted ...

  8. 线段树求逆序数方法 HDU1394&amp;&amp;POJ2299

    为什么线段树能够求逆序数? 给一个简单的序列 9 5 3 他的逆序数是3 首先要求一个逆序数有两种方式:能够从头開始往后找比当前元素小的值,也能够从后往前找比当前元素大的值,有几个逆序数就是几. 线段 ...

  9. HDU 1394 Minimum Inversion Number (线段树 单点更新 求逆序数)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给你一个n个数的序列,当中组成的数仅仅有0-n,我们能够进行这么一种操作:把第一个数移到最 ...

随机推荐

  1. [转]使用C#开发ActiveX控件全攻略

    前言: 这段时间因为工作的需要,研究了一下ActiveX控件.总结如下: 先说说ActiveX的基本概念. 根据微软权威的软件开发指南MSDN(Microsoft Developer Network) ...

  2. memcache 基础原理

    memcache是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发,但目前被许多网站使用以提升网站的访问速度,尤其对于一些大型的.需要频繁访问数据库的网站访问速 ...

  3. 学习Linux的正确姿势

    学习Linux的正确姿势 端正学习态度1.Linux不等于骇客(or Cracker).当然众所周知很多“黑客工具”都是Linux平台上的,我帮助过很多Linux小白发现他们殊途同归都是朝着类似Air ...

  4. python之路----网络编程--黏包

    黏包现象 让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd) res=subprocess.Popen(cmd.decode('utf-8'), shell ...

  5. Spring IOC 源码分析

    Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...

  6. 获取Json字符串中的key和value

    获取Json字符串中的key和value 在web项目中经常会用到json数据(如:struts2处理请求返回json数据给jsp解析),因此,JSONObject对象是必备的,这时就需要引入相关的j ...

  7. 20145205 武钰 《网络对抗》Exp8 Web基础

    一点题外话 本次实验我三号完成的,由于一些原因吧,一直没发博客,拖到了现在,这里说就是评判一下自己的懒惰. 实验后问题回答 (1)什么是表单 表单在网页中主要负责数据采集功能. 一个表单有三个基本组成 ...

  8. 20145307陈俊达《网络对抗》Exp6 信息搜集与漏洞扫描

    20145307陈俊达<网络对抗>Exp6 信息搜集与漏洞扫描 基础问题回答 哪些组织负责DNS,IP的管理? 全球根服务器均由美国政府授权的ICANN统一管理,负责全球的域名根服务器.D ...

  9. CodeForces 76A Gift - 最小生成树

    The kingdom of Olympia consists of N cities and M bidirectional roads. Each road connects exactly tw ...

  10. startActivityForResult( )用法

    一.与startActivity( )的不同之处 1, startActivity( ) 仅仅是跳转到目标页面,若是想跳回当前页面,则必须再使用一次startActivity( ). 2, start ...