逆序数的概念:对于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. linux服务器上nginx日志访问量统计命令

    linux服务器上nginx日志访问量统计命令 日志文件所在地方:/var/log/nginx/access_iqueendress.com.log/var/log/nginx/access_m.iq ...

  2. python3.4学习笔记(六) 常用快捷键使用技巧,持续更新

    python3.4学习笔记(六) 常用快捷键使用技巧,持续更新 安装IDLE后鼠标右键点击*.py 文件,可以看到Edit with IDLE 选择这个可以直接打开编辑器.IDLE默认不能显示行号,使 ...

  3. mysql 替换函数replace()实现mysql 替换字符串

    mysql 替换字符串的实现方法:mysql中replace函数直接替换mysql数据库中某字段中的特定字符串,不再需要自己写函数去替换,用起来非常的方便,mysql 替换函数replace()Upd ...

  4. MySQL Crash Course #10# Chapter 19. Inserting Data

    INDEX BAD EXAMPLE Improving Overall Performance Inserting Multiple Rows INSTEAD OF Inserting a Singl ...

  5. Linux 虚拟机安装vmware tools

    Linux Vmware tools安装步骤 1 在 vSphere Client 清单中,右键单击虚拟机,然后选择电源 > 开启.   2 单击控制台选项卡以确定客户机操作系统启动成功,并在需 ...

  6. linux django 知识点 安装mysql数据库 和 pycharm

     django 命令及相关知识点 1. 启动 pycharm 命令:sh pycharm.sh 2. 创建 django 项目 : django-admin.py startproject Hello ...

  7. 05: api认证

    1.1 api认证原理介绍 1.api认证原理:客户端生成秘钥 1) 客户端与服务器端有一个相同的字符串作为auth_key 2) 客户端使用encryption="auth_key|tim ...

  8. FATFS(A)

    (一),什么是文件管理系统 答:数据在PC上是以文件的形式储存在磁盘中的,这些数据的形式一般为ASCII码或二进制形式.简单点说就是:管理磁盘上的文件的方法的代码! 如:我们写到SD卡上面的数据管理一 ...

  9. CSS实现三角形、梯形、平行四边形、圆形、椭圆形、对话框、自适应正方形

    本文篇幅较长,希望能坚持看完,转载请注明出处,如果觉得好文请给个赞吧 CSS实现梯形 CSS实现三角形和梯形主要是依靠border是梯形的特性来做的,有点像相框的那种感觉. 首先我们先给一个正方形设置 ...

  10. 联想预装Win10/Win8换Win7 教程 以及svn使用教程

    1.换系统教程 http://ideapad.it168.com/thread-4869510-1-1.html http://jingyan.baidu.com/article/08b6a591c8 ...