逆序数的概念:对于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. 使用 amcharts 和 highcharts 绘制多曲线时间趋势图的通用方法

    工作中用到, 这里分享一下. 可以使用 amcharts 和 highcharts 在同一坐标中绘制多个对比曲线图. 当然, 对图形没有过多装饰, 可以参考 API 文档: highcharts:   ...

  2. Python: ljust()|rjust()|center()字符串对齐

    通过某种对齐方式来格式化字符串 ①对于基本的操作,可以使用字符串的ljust(),rjust(),center() ②函数format()同样可以用来很容易的对齐字符串,使用<,>,~

  3. Neutron网络学习

    学习 Neutron 系列文章: 转http://www.cnblogs.com/sammyliu/p/4622563.html (1)Neutron 所实现的网络虚拟化 (2)Neutron Ope ...

  4. MySQL Crash Course #05# Chapter 9. 10. 11. 12 正则.函数. API

    索引 正则表达式:MySQL only supports a small subset of what is supported in most regular expression implemen ...

  5. Python入门之面向对象的__init__和__new__方法

    Python入门之面向对象的__init__和__new__方法

  6. Java的各种加密算法

    Java的各种加密算法 JAVA中为我们提供了丰富的加密技术,可以基本的分为单向加密和非对称加密 1.单向加密算法 单向加密算法主要用来验证数据传输的过程中,是否被篡改过. BASE64 严格地说,属 ...

  7. JAVA第十周《网络编程》学习内容总结

    JAVA第十周<网络编程>学习内容总结 学习内容总结 1.初听到网络编程四个字可能会觉得很困难,实际上网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据,把数据发送到指定的位置, ...

  8. Python3基础 __repr__ 实例对象的名字,可以显示信息

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  9. sublimeText3最新教程-自带插件汉化(sublime-text_build-3175_amd64)

    一.可用注册码 1.更改dns 在linux下的目录是     /etc/hosts 在win7中,hosts文件的位置:C:\Windows\System32\drivers\etc 127.0.0 ...

  10. HDU 1247 Hat’s Words(字典树)题解

    题意:给一个字符串集,要你给出n个字符串s,使s能被所给字符串集中的两个相加所得(ahat=a+hat) 思路:简单字典树题,注意查询的时候要判断所指next是否为NULL,否则会RE非法访问. 代价 ...