归并法求逆序数

求逆序数

时间限制:2000 ms  |  内存限制:65535 KB

难度:5

 

描述

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

现在,给你一个N个元素的序列,请你判断出它的逆序数是多少。

比如 1 3 2 的逆序数就是1。

 

输入
第一行输入一个整数T表示测试数据的组数(1<=T<=5) 每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000) 随后的一行共有N个整数Ai(0<=Ai<1000000000),表示数列中的所有元素。
数据保证在多组测试数据中,多于10万个数的测试数据最多只有一组。
输出
输出该数列的逆序数
样例输入
2
2
1 1
3
1 3 2
样例输出
0
1
 1 //可以直接双重for循环
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<stdlib.h>
 5 #define N 1000010
 6 using namespace std;
 7 long long ans;
 8 int a[N];
 9
10 void merge(int s1,int e1,int s2,int e2)
11 {
12     int p1,p2,p;
13     int* temp = new int[e2-s1+5];
14     p=0;p1=s1;p2=s2;
15     while(p1<=e1&&p2<=e2)
16     {
17         if(a[p1]<=a[p2])
18         {
19             temp[p++]=a[p1++];
20             continue;
21         }
22         else
23         {
24             temp[p++]=a[p2++];
25             ans+=e1-p1+1;   //关键所在
26             continue;
27         }
28     }
29     while(p1<=e1) temp[p++]=a[p1++];
30     while(p2<=e2) temp[p++]=a[p2++];
31     int i;
32     for(i=s1;i<=e2;i++) a[i]=temp[i-s1];
33     delete temp;
34 }
35
36 void merge_sort(int s,int e)
37 {
38     int m;
39     if(s<e)
40     {
41         m=(s+e)/2;
42         merge_sort(s,m);
43         merge_sort(m+1,e);
44         merge(s,m,m+1,e);
45     }
46 }
47
48 int main()
49 {
50     int test;
51     scanf("%d",&test);
52     while(test--)
53     {
54         int n,i;
55         ans=0;
56         scanf("%d",&n);
57         for(i=0;i<n;i++)
58             scanf("%d",&a[i]);
59         merge_sort(0,n-1);
60         printf("%lld\n",ans);
61     }
62 }        

 

时间: 2024-09-24 13:12:42

归并法求逆序数的相关文章

【33】利用归并排序求逆序数对

题目:利用归并排序求解一个数组中的逆序数对 分析: 1. 什么是逆序数对,例如给定数组{7, 5, 6, 4},对于每个数num,如果num之前有多少个数大于num则说明num这个数构成逆序数对有多少个     7有0个,5有1个,6有1个,4有三个,因此数组中总的逆序数对为5. 2. 怎么利用归并排序来求逆序数对呢?    (1)假设数组为{7, 5, 6, 4}    (2)归并排序的递归树如下            (3)求逆序数对是在合并左右两个子序列的时候.在merge函数中,左右子序

HDU 1394 线段树单点更新求逆序数

题意:给出含有0 ~n-1 N个数组成的序列,有N次操作,每次把第一个数放到数列的最后,问这几次数列操作中最小的逆序数的值. 单点更新就可以,每一输入一个数,先查询有几个比这个数大的,再将这个值插入线段树中. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 5005 struct node { i

hdu1394 线段树求最小逆序数

hdu 1394 http://acm.hdu.edu.cn/showproblem.php?pid=1394 用线段树求逆序数,例如要求x的逆序数只需要访问(x+1,n)段有多少个数,就是x的逆序数.还有就是求最小逆序数的时候有个巧妙的想法,当把x放入数组的后面,此时的逆序数应该为x没放入最后面之前的逆序总数加上(n-x)再减去(x-1):sum = sum+(n-x[i])-(x[i]-1). 线段树 #include<cstdio> #include<algorithm> #

经典算法(9) 从归并排序到数列的逆序数对(微软笔试题)

首先来看看原题 微软2010年笔试题 在一个排列中,如果一对数的前后位置与大小顺序相反 ,即前面的数大于后面的数,那么它们就称为一个逆序数对.一个排列中逆序的总数就称为这个排列的逆序 数.如{2,4,3,1}中,2和1,4和3,4和1,3和1是逆序数对,因此整个数组的逆序数对个数为4,现在给定 一数组,要求统计出该数组的逆序数对个数. 计算数列的逆序数对个数最简单的方便就最从前向后依 次统计每个数字与它后面的数字是否能组成逆序数对.代码如下: #include <stdio.h> int ma

java递归法求字符串逆序_java

本文实例讲述了java递归法求字符串逆序的方法.分享给大家供大家参考.具体实现方法如下: public static String reverseString(String x) { if(x==null || x.length()<2) return x; return reverseString(x.substring(1,x.length()))+ x.charAt(0); } 希望本文所述对大家的java程序设计有所帮助. 以上是小编为您精心准备的的内容,在的博客.问答.公众号.人物.课

c语言-C语言 关于用矩形法求定积分

问题描述 C语言 关于用矩形法求定积分 #include""stdio.h""#include""math.h""int main(){ double fun1(double x); double fun2(double x); double fun3(double x); double calc(double adouble bdouble (*p)(double)); int type; double ab; double

JS实例教程:用6N±1法求素数

用6N±1法求素数任何一个自然数,总可以表示成为如下的形式之一:6N,6N+1,6N+2,6N+3,6N+4,6N+5 (N=0,1,2,-)显然,当N≥1时,6N,6N+2,6N+3,6N+4都不是素数,只有形如6N+1和6N+5的自然数有可能是素数.所以,除了2和3之外,所有的素数都可以表示成6N±1的形式(N为自然数).根据上述分析,我们可以构造另一面筛子,只对形如6 N±1的自然数进行筛选,这样就可以大大减少筛选的次数,从而进一步提高程序的运行效率和速度. 以下代码需要自然数大于10fu

java-回溯法求子集问题。。

问题描述 回溯法求子集问题.. 问题描述:子集和问题的一个实例为.其中,S={X1,X2,X3,--,XN}是一个正整数的集和,C是一个正整数.子集和问题判定是否存在S的一个子集S1,使得S1中的所有元素加起来正好等于C.

RC4编程为何加密结果是乱码,而且求逆解码的结果与明文不同,多谢~

问题描述 RC4编程为何加密结果是乱码,而且求逆解码的结果与明文不同,多谢~ #include #include using namespace std; void main() { char k[256]; int s[256],t[256]; cout<<"please input key"<<endl; cin>>k; cout<<endl; for(int i=0;i<256;i++) { s[i]=i; t[i]=k[i%