逆序对

逆序对

逆序对:满足i<j且a[i]>a[j]的所有的(a[i],a[j])对的个数。

 

I.正常的方法O(n^2):

可以从i或j的角度出发

Code:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #define maxn 10000
 4  
 5 int main()
 6 {
 7     long a[maxn+1],n,ans,i,j;
 8     scanf("%ld",&n);
 9     for (i=1;i<=n;i++)
10         scanf("%ld",&a[i]);
11     ans=0;
12     //i<j
13     for (i=1;i<n;i++)
14         for (j=i+1;j<=n;j++)
15             //a[i]>a[j]
16             if (a[i]>a[j])
17                 ans++;
18     printf("%ld\n",ans);
19     ans=0;
20     //i>j
21     for (i=n;i>1;i--)
22         for (j=i-1;j>=1;j--)
23             //a[i]<a[j]
24             if (a[i]<a[j])
25                 ans++;
26     printf("%ld\n",ans);
27     return 0;
28 }
29 /*
30 10
31 5 3 2 10 1 6 9 4 8 7
32 4+2+1+6+0+1+3+0+1+0=18
33 3+2+4+1+1+4+0+2+1+0=18
34 */

 

 

 

 

II.有两种方法求逆序对使得时间复杂度为O(nlogn):

1.归并排序+统计

2.离散化+树状数组

 

1.归并排序+统计

 1 Code:
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #define maxn 100000
 5  
 6 ///mergesort:O(nlogn)
 7  
 8 long a[maxn+1],t[maxn+1];
 9 //max_ans:maxn*(maxn-1)/2=4999950000 , use long long
10 long long ans=0;
11  
12  
13 void mergesort(long l,long r)
14 {
15     if (l==r)
16         return ;
17     long mid,x,y,z,i;
18     mid=(l+r)/2;
19     mergesort(l,mid);
20     mergesort(mid+1,r);
21     for (i=l;i<=r;i++)
22         t[i]=a[i];
23     x=l;
24     y=mid+1;
25     z=l;
26     while (x<=mid && y<=r)
27     {
28         //两个数相等时让左边的数先加,因为相同的数不能凑成一对
29         if (t[x]<=t[y])
30         {
31             a[z]=t[x];
32             x++;
33             //a[x] > a[mid+1]~a[y-1]
34             ans+=(y-mid-1);
35         }
36         else if (t[x]>t[y])
37         {
38             a[z]=t[y];
39             y++;
40         }
41         z++;
42     }
43     if (x<=mid)
44     {
45         //a[x] > a[mid+1]~a[r]
46         ans+=(mid-x+1)*(r-mid);
47         while (z<=r)
48         {
49             a[z]=t[x];
50             x++;
51             z++;
52         }
53     }
54     else
55     {
56         while (z<=r)
57         {
58             a[z]=t[y];
59             y++;
60             z++;
61         }
62     }
63 }
64  
65 int main()
66 {
67     long n,i;
68     scanf("%ld",&n);
69     for (i=1;i<=n;i++)
70         scanf("%ld",&a[i]);
71     mergesort(1,n);
72     printf("%lld\n",ans);
73     return 0;
74 }
75 /*
76 Input:
77 10
78 5 3 2 10 1 6 9 4 8 7
79 Output:
80 18
81 */

 

 

 

2.离散化+树状数组

Code:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #define maxn 10000
 4  
 5 //离散化(数为1~n;或数很集中除外)+树状数组(求a[k+1]~a[n]中小于a[k]的数)
 6  
 7 struct node
 8 {
 9     long value,pos;
10 }s[maxn+1];
11 //n个数,最多有n个不同的数值
12 long a[maxn+1],c[maxn+1];
13  
14 int cmp(const void *a,const void *b)
15 {
16     if ((*(struct node *)a).value<(*(struct node *)b).value)
17         return -1;
18     else
19         return 1;
20 }
21  
22 int main()
23 {
24     long n,i,t,v;
25     long long ans;
26     scanf("%ld",&n);
27     for (i=1;i<=n;i++)
28     {
29         scanf("%ld",&s[i].value);
30         s[i].pos=i;
31     }
32     //排序
33     qsort(s+1,n,sizeof(struct node),cmp);
34     //离散化(保留数的大小关系;数值无所谓,舍弃之)
35     //设置最小值为2,是为了之后比(a[i]-1)小的数
36     t=1;
37     for (i=1;i<=n;i++)
38     {
39         t++;
40         a[s[i].pos]=t;
41         while (i<n && s[i].value==s[i+1].value)
42         {
43             i++;
44             a[s[i].pos]=t;
45         }
46     }
47     //树状数组
48     for (i=1;i<=t;i++)
49         c[i]=0;
50     ans=0;
51     for (i=n;i>=1;i--)
52     {
53         //获得小于等于(a[i]-1),即小于a[i]的数
54         v=a[i]-1;
55         while (v>0)
56         {
57             ans+=c[v];
58             v=v-(v & (-v));
59         }
60         //添加a[i]
61         v=a[i];
62         while (v<=t)
63         {
64             c[v]++;
65             v=v+(v & (-v));
66         }
67     }
68     printf("%lld\n",ans);
69     return 0;
70 }
71 /*
72 Input:
73 10
74 5 3 2 10 1 6 9 4 8 7
75 Output:
76 18
77 */
78  

 

posted @ 2017-05-25 21:15  congmingyige  阅读(170)  评论(0编辑  收藏  举报