求逆序对

给定一个序列a1,a2,…,an,如果存在iaj,那么我们称之为逆序对,求逆序对的数目 

Input

第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数。 
N<=10^5。Ai<=10^5

Output

两行,第一行为所有逆序对总数,第二行为本质不同的逆序对总数。 

Sample Input

4 
3 
2 
3 
2 

Sample Output

3
1

sol:利用归并排序的思想求逆序对。

归并排序的核心思想是分治,当我们将a数组里的数分得足够小的时候,开始逐一合并过程,合并时,分别用指针i,j指向两边的头(即i=l, j=mid+1),分别往后扫,每次取出两个指针所指的数中较小的放入b数组。如果取出的是左边的数放入b数组,则左右两边的数不构成逆序对,如果是右边的数放入b数组,这时a[i]>a[j],说明i~mid间的所有数都比a[j]大(因为左边有序,右边有序),此时,逆序对数增加mid-i+1个。

 1 #include <cstdio>
 2 int a[30010],b[30010];
 3 int ans=0;
 4 int n;
 5 void merge(int s,int t)
 6 //s是左边界,t是右边界 
 7 {
 8     if(s==t)return;
 9     int mid=s+t>>1;
10     merge(s,mid); //左边排好 
11     merge(mid+1,t);//右边排好 
12     int i=s,j=mid+1;
13     int p=s-1;//记一个位置 
14     while(i<=mid&&j<=t) //但没有过界的时候 
15     {
16         if(a[i]<=a[j]) //将a[i]放入b数组 
17         {
18             b[++p]=a[i];
19             i++;
20         }
21         else
22         {
23             b[++p]=a[j];//将a[j]放入b数组 
24             j++;
25             ans+=mid+1-i;//逆序对增加mid+1-i个 
26         }
27     }
28     while(j<=t)//把a[j]剩下的全部放入b数组 
29     {
30         b[++p]=a[j];
31         j++;
32     }
33     while(i<=mid)//把a[i]剩下的全部放入b数组 
34     {
35         b[++p]=a[i];
36         i++;
37     }
38     for(int i=s;i<=t;i++) 
39     a[i]=b[i];
40 }
41 int main()
42 {
43     scanf("%d",&n);
44     for(int i=1;i<=n;i++)
45     scanf("%d",&a[i]);
46     merge(1,n);
47     printf("%d",ans);
48 }

原文地址:https://www.cnblogs.com/cutepota/p/12129232.html