题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1019

题意:中文题诶~

思路:

方法1:归并排序~

归并排序过程为,先不断二分直至每组元素数目为一,此时我们可以将每组元素看做已排序状态;然后在回溯过程把这些组两两合并,并在合并过程中排序;

那么我们每一次合并都得到已排序的组,直至合并为一个组,即已排序数组;

那我们如何用上述过程统计逆序对数目呢~这就需要分析一下合并的具体过程啦;

假设我们现在有两个已排序数组a[p, m], a[q, y] 依次比较a[p], a[q],将其中较小的存入临时数组t中,那么最终得到的t数组就是a[p, y]区间所有元素的已排序状态啦,然后将t数组覆盖a[p, y]数组,那么a[p, y]就是已排序状态了啦~  发现了有木有,如果我们在某一次操作中将右边的元素a[q]存入t中,那么a[q]大于当前左边数组a[p, m]的所有元素,即a[q]与数组a[p, m]中每个元素都能组成一个逆序对,对于a[q]元素我们可以得到(m-p)个逆序对 (数组a[p, m]区间为左闭右开即为区间

[p, m));对于数组a[p, m], a[q, y],假设元素gg, jj可以组成逆序对,我们可以将区间[p, y)里面可以组成逆序对的情况分为gg, jj都在 左边区间或者右边区间,gg, jj分别位于两个区间中,不过我们不难发现前两种情况就是合并前的第三种情况,例如对于数组a[p, m] 和a[q, y]我们求出gg, jj分处于两边的逆序对数为ans, 那么在下一次合并过程中,对于a[p', p] , a[p, q],则ans为gg, jj都位于a[p, q]中的逆序对数; 从这里我们可以发现虽然我们将逆序岁数分三种情况,事实上我们只要累计第三中情况的逆序对数就好啦~

代码:

 #include <bits/stdc++.h>
#define MAXN 50010
using namespace std; int ans=; void teger_sort(int* a, int* t, int x, int y){
if(y-x>){ //**递归至单个元素为一组
int m=(y+x)>>;
int p=x, q=m, i=x;
teger_sort(a, t, x, m); //***左递归
teger_sort(a, t, m, y); //***右递归
while(p<m||q<y){ //**合并
if(q>=y||(p<m&&a[p]<=a[q])){
t[i++]=a[p++]; //**将左边元素复制到临时数组
}else{
t[i++]=a[q++]; //**将右边元素复制到临时数组
ans+=m-p; //**累计逆序对的数目
}
}
for(int i=x; i<y; i++){ //**将临时数组里已排序的元素还原到原数组
a[i]=t[i];
}
}
} int main(void){
int n, a[MAXN], t[MAXN];
scanf("%d", &n);
for(int i=; i<n; i++){
scanf("%d", &a[i]);
}
teger_sort(a, t, , n);
printf("%d\n", ans);
return ;
}

方法2:树状数组~

首先我们先建立一个数轴,对于输入的数据x,我们给数轴上的x标记1(初始时标记都为0啦~),数轴上x前面的数都比x小,也就是说x前面的所有标记的数都是不可以与x组成逆序对的数,假设x是第i个输入,用sum(x)表示x以及前面所有标记的和,即sum=x前面i-1个元素中比x小的个数+1(因为x本身不能和自己组成逆序对嘛),那么i-sum(x)就是x和其前面的元素可以组成的逆序对数咯,累加所有元素和其前面的元素组成的逆序对数就是我们要的答案啦~
对于这里的数轴我们可以直接用数组标记就好了,不过这里的x数据范围是1e9,直接开数组肯定开不下啦,用map会超时,所以我们需要对输入的数据先hash一下~
可是这个思路如果直接暴力的话还是会超时,不过,求sum(x)就是区间求和嘛,区间求和我们可以用树状数组或者线段树嘛,这里树状数组和线段树的效果一样,我们就用代码更简单的树状数组啦;要讲树状数组的话比较麻烦,这里就给出一个本人觉得讲的不错的树状数组博客好了~
http://blog.csdn.net/ljd4305/article/details/10101535
 
代码:
 
 #include <bits/stdc++.h>
#define MAXN 50010
using namespace std; int tree[MAXN], n; int lowbit(int x){ //**得到pow(2, k), 其中k为x的二进制末尾0的个数即x二进制最低位1的值
return x&(-x);
} void update(int x, int d){ //**向上更新父节点及根节点~
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
} int sum(int x){ //**向下求和
int ans=;
while(x>){
ans+=tree[x];
x-=lowbit(x);
}
return ans;
} int main(void){
pair<int, int> p[MAXN];
int gg[MAXN], ans=;
scanf("%d", &n);
for(int i=; i<=n; i++){ //**hash
scanf("%d", &p[i].first);
p[i].second=i
}
sort(p+, p+n+);
for(int i=; i<=n; i++){
gg[p[i].second]=i;
}
for(int i=; i<=n; i++){
update(gg[i], ); //因为x不能和自己组成逆序对,要减去,所以我们要先更新再求和,更新后sum(x)就包括了x了嘛~
ans+=i-sum(gg[i]);
}
printf("%d\n", ans);
return ;
}
 

51nod1019逆序数(归并排序/树状数组)的更多相关文章

  1. 2018年全国多校算法寒假训练营练习比赛(第五场):A题:逆序数(树状数组or归并排序)

    题目描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.比如一个序列为4 5 1 3 2, 那么这个序列 ...

  2. 剑指 Offer 51. 数组中的逆序对 + 归并排序 + 树状数组

    剑指 Offer 51. 数组中的逆序对 Offer_51 题目描述 方法一:暴力法(双层循环,超时) package com.walegarrett.offer; /** * @Author Wal ...

  3. CF #301 E:Infinite Inversions(逆序数,树状数组)

    A-Combination Lock  B-School Marks   C-Ice Cave   D-Bad Luck Island   E-Infinite Inversions E:Infini ...

  4. H - 逆序数(树状数组)

    在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 如2 4 3 1中,2 1,4 3,4 1,3 1是逆序 ...

  5. NYOJ 117 求逆序数 (树状数组)

    题目链接 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出 ...

  6. AcWing 107. 超快速排序(归并排序 + 逆序对 or 树状数组)

    在这个问题中,您必须分析特定的排序算法----超快速排序. 该算法通过交换两个相邻的序列元素来处理n个不同整数的序列,直到序列按升序排序. 对于输入序列9 1 0 5 4,超快速排序生成输出0 1 4 ...

  7. 洛谷 P1908 逆序对 Label:归并排序||树状数组 不懂

    题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定 ...

  8. POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)

    树状数组求逆序对   转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...

  9. Day2:T4求逆序对(树状数组+归并排序)

    T4: 求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I 设B[]=A[]-M*( ...

随机推荐

  1. C#网络爬虫 WebUtility使用 转义字符 urlCode

    背景: 在C#写网络爬虫时候,有时候需要将html中的转义字符进行处理,还有网址中的中文处理 一.html转义字符处理 1.ASP.NET中的html解析 HttpUtility.HtmlDecode ...

  2. asp.net的sql防注入和去除html标记的方法

    一. // <summary> /// 过滤标记 /// </summary> /// <param name="NoHTML">包括HTML, ...

  3. 2015年最有价值的30个响应式WORDPRESS主题

    http://www.chinaz.com/design/2015/0521/408204.shtml 必须承认,Wordpress依然是目前最流行.最易用的内容管理系统,合理地使用Wordpress ...

  4. jQuery学习:用按键移动方块

    <!doctype html> <html> <head> <meta charset="utf-8"> <style typ ...

  5. IBM B16光纤交换机ZOON划分方法

      一.ZOON的含义及划分原则     Zoon在光纤存储交换机中的功能类似于以太网交换机VLAN的作用,主要是为了在一台交换机划分出多个逻辑区,用于防范不同应用的存储连接发起广播包,提高光纤交换机 ...

  6. iOS开发——UI进阶篇(十六)Quartz2D实战小例子

    一.画线 只有在drawRect中才能获取到跟view相关联的上下文 - (void)drawRect:(CGRect)rect {} 一条线 // 1.获取跟当前View相关联的layer上下文(画 ...

  7. ionic不同view跳转到同一个

    ionic不同view跳转到同一个 view并保留历史的路由设计 上代码:state 里面新加一个状态 .state("other", { url: "/other&qu ...

  8. 本科小白学ROS 和 SLAM(一):杂谈

    本人最近才迷恋上ROS(Robot Operating System),准确的说应该是6月中旬,具体的记不清了(可能是年纪大了,容易健忘).对于一个电子DIY的狂热爱好者来说,我在校的梦想就是做一个属 ...

  9. js清空array数组的方法

    方式1,splice Js代码   ,,,}; ary.length = ; Java中会报错,编译通不过. 而JS中则可以,且将数组清空了,如 Js代码   var ary = [1,2,3,4]; ...

  10. 极客DIY:制作一个可以面部、自主规划路径及语音识别的无人机

    引言 现在大部分无人机厂商都会为第三方开发者提供无人机API接口,让他们更容易地开发无人机飞行控制应用程序,让无人机想怎么玩就怎么玩.有的API接口可以帮助开发者开发基于Web版的APP.手机APP甚 ...