逆序对

逆序对是啥呢?

就是说有一个数组:3,1,4,5,2

然后逆序可以理解为默认升续,但是数对(两个)是降序排列,和升序相反,所以叫逆序。

我们的目的是求数目QWQ数目QW数目QWQ不是他长啥样

我查到的有三种,一种是暴力枚举来找逆序对时间复杂度n方,我们今天就讲这个(唔)。

        一种是利用并归排序来找逆序对数量,这个我不会(唔)。

        最后一种是利用树状数组求逆序对,所以我们不讲这个。

  恩,我感觉我讲完了可以收尾了(~ ̄▽ ̄)~。。。

好,那么正题,我们主要讲树状数组的逆序对,对于暴力太简单,对于并轨我不会QWQ。

那么我们先来看看上边的数组3,1,4,5,2,我们我要找的他逆序对怎么办呢

小A(举手)我们从第一个数开始向最后一个数枚举就好了,找完一个找下一个。

(凳子糊上去),好了,我们继续。

那么树状数组怎么做呢?

首先,我们要对数据排序:确认是大的在前小的在后(为什么呢,不解释)

这样我们就可以每次都用O(1)的时间完成取数的过程。然后将取来的数放入c数组中,位置放在他本来的排列位置。

然后我们先将最大的数5放进去,放入对应的位置并标记为1表示这里有一个数了,同时(这里是重点重点重点!!!!!),我们要检测一下他前面有没有已经进入c数组的数,如果有,那么我们就找到一个逆序对了:

然后再把第二大的数放进去,然后还是要找:

经过一直坚持不懈的找,我们终于找到了这样一个数:

 

当我们把2放入时,这时候前边终于有数了,那么前边有几个数我们答案加几,所以答案加3,我们找到三个逆序对。

 

 

当我们找完时应该是这样的,这时候最后一个数也找完了,又找到一个逆序对,所以答案再加1;最终的答案就是4了。

看了这么多你一定想说,那树状数组有什么用呢QWQ,其实树状数组的用处就在这,他的主要用途就是求前边到底有几个1的如果你不知道啥是树状数组,戳这里http://www.cnblogs.com/fuyun-boy/p/5913438.html

所以过程很简单,代码也很简单:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 //==================================================== 
 5 struct NODE{  //计数和数本来位置的函数 
 6    int first,second;
 7 }a[500];
 8 //==================================================== 
 9 int c[500],N,ans=0;
10 //==================================================== 
11 bool cmp(NODE a,NODE b)  //比较函数,确认大的在前 
12 {
13    return a.first>=b.first?true:false;
14 }
15 //==================================================== 
16 void ADD(int x,int y)
17 {
18    for(int i=x;i<=N;i+=i&(-i)){
19       c[i]+=y;
20    }
21 }
22 //==================================================== 
23 int sum(int x)
24 {
25    int SUM=0;
26    for(int i=x;i>=1;i-=i&(-i)){
27       SUM+=c[i];
28    }
29    return SUM;
30 }
31 //==================================================== 
32 void init()
33 {
34    int k;
35    cin>>N;
36    for(int i=1;i<=N;i++){  //输入n个数 
37       cin>>a[i].first;   //数的本体 
38       a[i].second=i;     //数的位置,因为一会要放入c数组 
39    }
40    sort(a+1,a+1+N,cmp);  //排序,为了取数方便 
41 }
42 //==================================================== 
43 void work()
44 {
45    for(int i=1;i<=N;i++){  //对N个数放入c数组并且计算是否前边有数 
46       ans+=sum(a[i].second);  //树状数组添加 
47       ADD( a[i].second, 1 );  //树状数组求前边所以数的和 
48    }
49 }
50 //==================================================== 
51 int main()
52 {
53    init();  //初始化 
54    work(); //计算 
55    cout<<ans; //输出答案 
56    system("pause");
57    return 0;
58 } 

 

posted on 2016-11-07 15:11  fuyun_boy  阅读(557)  评论(0编辑  收藏  举报

导航