逆序数

POJ 2299树状数组求逆序对

风流意气都作罢 提交于 2020-01-08 13:06:52
求逆序对最常用的方法就是树状数组了,确实,树状数组是非常优秀的一种算法。在做POJ2299时,接触到了这个算法,理解起来还是有一定难度的,那么下面我就总结一下思路: 首先:因为题目中a[i]可以到999,999,999之多,在运用树状数组操作的时候,用到的树状数组C[i]是建立在一个有点像位存储的数组的基础之上的,不是单纯的建立在输入数组之上。 比如输入一个9 1 0 5 4(最大9) 那么C[i]树状数组的建立是在: 下标 0 1 2 3 4 5 6 7 8 9 –——下标就要建立到9 数组 1 1 0 0 1 1 0 0 0 1 –——通过1来表示存在 现在由于999999999这个数字相对于500000这个数字来说是很大的,所以如果用数组位存储的话,那么需要999999999的空间来存储输入的数据。 这样是很浪费空间的,题目也是不允许的,所以这里想通过离散化操作。 那么怎么离散化操作呢?离散化是一种常用的技巧,有时数据范围太大,可以用来放缩到我们能处理的范围,必要的是建立一个结构体a[n],v表示输入的值,order表示原i值,再用一个数组aa[n]存储离散化后的值 例如: i:1 2 3 4 5 v:9 0 1 5 4 sort:0 1 4 5 9 order:2 3 5 4 1 aa:5 1 2 4 3 //建立映射:aa[a[i].order]=i;

拼图小游戏的逆序数

南笙酒味 提交于 2020-01-07 00:21:34
逆序数 首先前言:逆序数和拼图有啥关系呢,逆序数是啥 在拼图中,逆序数为偶数,才能拼图成功,奇数是不能成功的!! 逆序数:通过百度查询,得知:一个排序中所有逆序的总数和叫做逆序数; 比如: 4132 > 这是一个4小块的拼图 它这里的倒序有 41,43,42,32 所以这里的逆序数就是4(偶数); 所以,我们只需要关注逆序数就可以,它的前提就是 前面大于后面! let arr3 = []; let a = 0; for(let i = 0;i<this.len;i++){ arr3.push( arr2[i][2] ); } for(let i = 0;i<this.len;i++){ let b = arr3[i]; for(let j = i;j<this.len;j++){ let c = arr3[j]; if(b>c){ a += 1; } } }if(a%2 == 0){//偶数 console.log("加油~"); }else{ console.log("你不会成功的!"); //this.ding();//重复执行代码(随机) return false; } -webkit-user-select:none; -moz-user-select:none; -ms-user-select:none; user-select:none; 来源: https://www

POJ1007 DNA Sorting 水题

人走茶凉 提交于 2019-12-20 04:22:01
题意:给你一个DNA的序列,给定逆序数的定义,叫你按逆序数从小到大排序输出。 其实很简单。 只不过为了排序,弄个结构体出来比较方便。 #include<iostream> #include<queue> #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) #include<algorithm> using namespace std; const int N=55,M=105; int n,m; char str[M][N]; struct Node { int id,num; }node[M]; int a,c,g,t; int count(char a) { switch(a) { case 'A': a++; return c+g+t; case 'C': c++; return g+t; case 'G': g++; return t; case 'T': t++; return 0; } } bool cmp(const Node&a,const Node&b) { return a.num<b.num; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { a=0,t=0,g=0,c=0; scanf("%s",str[i]+1); node[i]

数据结构 表 逆序数

僤鯓⒐⒋嵵緔 提交于 2019-12-09 17:48:27
算法与数据结构实验题 2.10 逆序数 ★实验任务 Nk 最近喜欢上了研究逆序数,给出一个由 1…n 组成的数列 a1,a2,a3…an, a1的逆序数就是在 a2…an 中,比 a1 小的数的数量,而 a2 的逆序数就是 a3…an 中比 a2 小的数的数量,以此类推。 例如,数列 5,3,4,2,1 的逆序数序列就是 4,2,2,1,0. 那么,如果给出一个数列的逆序数序列,你能不能还原得到他的原数列? ★数据输入 每个测试数据是一个正整数 n。代表数列长度(1<=n<=500),并且原数列中的值的范围是[1,n]。 然后输入 n 个正整数 ai(0<=ai<n)。 ★数据输出 输出原始数列,两个数字间中间用空格隔开 分析: 逆序数的意思就是 在当前位置的后面有多少个比他小的数,根据这个性质,就可以做了 由于数列长度只有500 算法复杂度为O(n^2) 一定不会超时 代码如下: # include <bits/stdc++.h> # define LL long long # define ms(s) memset(s, 0, sizeof(s)) # define REP(i, a, b) for(int i = (a); i < (b); i++) # define INF 0X7fffffff using namespace std ; const int maxn =

ACM 逆序对(逆序数)总结

匿名 (未验证) 提交于 2019-12-03 00:43:02
最近做题遇到几次逆序数了,今天总结一下,以后遇到了再也不怕了。 首先说明一下什么是逆序数,下面是百度的 定义 : 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个 逆序 。一个排列中逆序的总数就称为这个排列的 逆序数 。 如2431中,21,43,41,31是逆序,逆序数是4。 ①如何求逆序数 方法如下: 考察每一位,判断从这一位往后有多少小于该位的,结果累加,得到最后结果。 至于为什么,我也不知道,反正我感觉挺好理解的。 ②如何用算法实现 当然,对于上述简单的过程,我们可以用两个for循环直接暴力,但是,这种方法一般都太low了,复杂度太高。 高效的方法有 : 归并排序、线段树、树状数组。 个人建议使用线段树求解,因为线段树在很多地方都有应用。 对于归并排序和树状数组,我就不解释了,因为归并排序一搞就忘记了而且用处不大,想了解的这里给出一篇博客 https://blog.csdn.net/acm_jl/article/details/51147010 例题是 HDU 1394,然后做完这个可以再写一下POJ 2299 HDU 1394的解析如下 https://www.cnblogs.com/qlky/p/5693747.html 然后我写的是POJ 2299 下面开始解析,当然,大家一定要有一定线段树的基础 算法的思想还是最基础的思想

计算一个数的阶乘和一个列表的逆序数

谁说胖子不能爱 提交于 2019-12-01 13:04:07
问题1:计算一个数的阶乘,也是一个全排列的问题。 比如:将数字1,2,3按照不同元素排成一列,总共有多少种排法? 3*2*1=6。也就是数字3的阶乘。 那么怎么用程序来实现呢? def factorial(num): """ 递归算法 :param num: :return: """ if num == 1: return 1 return num * factorial(num - 1) 阶乘的递归算法 在递归函数中,由于会有函数栈帧的开销,所以它的运行效果并不如非递归函数的好。 def factorial1(num): """ 非递归算法 :param num: :return: """ res = 1 while num > 0: res *= num num -= 1 return res 阶乘的循环实现 问题2:计算一个数列的逆序数。 逆序数:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。一个排列中所有逆序总数叫做这个排列的逆序数。也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。

树状数组求逆序数+离散化

前提是你 提交于 2019-11-27 02:39:53
逆序对指的是一个序列中有两个数ai和aj,i<j&&ai>aj,即它们下标与数值的增减不一致,那么对于这个问题:求一个序列中逆序对的个数,该如何解决呢? 树状数组求逆序的思想事实上和树状数组关系不大,以下图为例(自己画的,丑:): 如上图,第一次将第一个数1对应的a[1]++,这时还看不出来,再将4对应的a[4]++,同理a[2]++……即将n对应的a[n]++,这样做,就可以将一个无序的序列变得有序,同时a数组也表示了对应下标的数是否出现/处理过,而且当只有i个元素变换之时,剩余元素不会对接下来的操作造成影响,现在给出计算到2时的图片: 那么,对于最新处理的2或任意一个n(设下标为i)来说,前i个数中,比它小及其本身的数的个数,就是前i项的前缀和,因为排在原序列中i之后的数尚未处理,而已处理的a中比他小的数必然在它前面,且对应a[]值为1,那么,已处理的i个数中,比这个数n大的数的个数,也就是这一个数的逆序对数,就是i-getsum(n),而前缀和的求值与a数组的修改、维护,就可以交给树状数组了: 来源: https://blog.csdn.net/QGK_King/article/details/98486541

树状数组求逆序数讲解

主宰稳场 提交于 2019-11-26 19:56:06
树状数组求逆序对 树状数组可以用nlogn的算法做到求出逆序对.但这里着重讲树状数组的原理与求法. 树状数组最常用的方面就是用来求逆序对, 普通方法需要n^2的复杂度, 而树状数组只需要用nlogn的复杂度, 所以是很好的优化, 关键在于内部函数lowbit的应用. 下面是树状数组的结构图 : 当数据的范围较小时,比如maxn=100000,那么我们可以开一个数组c[maxn],来记录前面数据的出现情况,初始化为0;当数据a出现时,就令c[a]=1。 这样的话,欲求某个数a的逆序数,只需要算出在当前状态下c[a+1,maxn]中有多少个1,因为这些位置的数在a之前出现且比a大。 但是若每添加一个数据a时,就得从a+1到 maxn搜一遍,复杂度太高了。 树状数组却能很好的解决这个问题,可以把数一个个插入到树状数组中, 每插入一个数, 统计比他小的数的个数,对应的逆序为 i - getsum( c[i] ),其中 i 为当前已经插入的数的个数, getsum( c[i] )为比 c[i] 小的数的个数,i- getsum( c[i] ) 即比c[i] 大的个数, 即逆序的个数。最后需要把所有逆序数求和,就是在插入的过程中边插入边求和. 举个例子:有5个数,分别为5 3 4 2 1,当读入数据a=5时,c为:0,0,0,0,1;d为:0,0,0,0,1;当读入数据a=3时,c为:0,0