逆序数的概念:对于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. Ignite集群管理——基于静态IP的节点发现

    Ignite作为分布式内存,集群管理必不可少,Ignite支持基于组播,静态IP,Zookeeper,JDBC等方式发现节点,本文主要介绍基于静态IP的节点发现. 两个最重要的TCP通信设置类: 1. ...

  2. python实现常量const

    新建const.py: #-*-coding:UTF-8-*- #Filename: const.py # 定义一个常量类实现常量的功能 # # 该类定义了一个方法__setattr()__,和一个异 ...

  3. python3.4学习笔记(十) 常用操作符,条件分支和循环实例

    python3.4学习笔记(十) 常用操作符,条件分支和循环实例 #Pyhon常用操作符 c = d = 10 d /= 8 #3.x真正的除法 print(d) #1.25 c //= 8 #用两个 ...

  4. 百度云盘-真实地址 F12 控制台

    $.ajax({ type: "POST", url: "/api/sharedownload?sign="+yunData.SIGN+"&t ...

  5. 怎样将一个整数转化成字符串数,并且不用函数itoa

    #include<iostream> using namespace std; int main() { , j = , i = ; ], str[]; while (num) { tem ...

  6. OpenCV中HSV颜色模型及颜色分量范围

    HSV颜色模型 HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)..这 ...

  7. 20145225《网络对抗》Exp8 Web基础

    参考博客:5215~ 这次试验,没搞懂,只做了一部分,求老师酌情给分啊 啊啊 基础问题回答 什么是表单? 表单是一个包含表单元素的区域,表单元素是允许用户在表单中(比如:文本域.下拉列表.单选框.复选 ...

  8. word2vec 中的数学原理详解(一)目录和前言【转】

    本文转载自:https://blog.csdn.net/itplus/article/details/37969519 word2vec 是 Google 于 2013 年开源推出的一个用于获取 wo ...

  9. jz2440移植QT5.6【学习笔记】【原创】

    平台:jz2440 作者:庄泽彬(欢迎转载,请注明作者) 交叉编译工具:arm-linux-gcc (GCC)4.4.3 linux:linu3.4.2 PC环境:ubuntu18.04 一.修改/o ...

  10. POJ 2348 Euclid's Game(博弈)题解

    题意:有a,b两个数字,两人轮流操作,每次可以选择两个之中较小的数字,然后另一个数字减去选择数字的任意倍数(不能减到负数),直到其中一个为0,不能操作为败 思路:这题用博弈NP思想,必败点和必胜点之间 ...