在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。
Input
第1行:N,N为序列的长度(n <= 50000) 第2 - N + 1行:序列中的元素(0 <= A[i] <= 10^9)
Output
1
输出逆序数
Input示例
4 2 4 3 1
Output示例
4
#include<iostream> #include<algorithm> using namespace std; int a[100001],c[100001]; int sum=0; void merges(int l,int mid,int r){ int q,m,p; q=p=l;m=mid+1; while(p<=mid&&m<=r){ if(a[p]<=a[m]){ c[q++]=a[p++]; } else {c[q++]=a[m++]; sum+=(m-q);} } while(p<=mid) c[q++]=a[p++]; while(m<=r) c[q++]=a[m++]; for(int j=l;j<q;j++) a[j]=c[j]; } void merge_sort(int l,int r){ int q,p,m; if(l<r){ int mid=(l+r)/2; merge_sort(l,mid); merge_sort(mid+1,r); merges(l,mid,r); } } int main(){ int n,j; cin>>n; for(j=0;j<n;j++){ cin>>a[j]; } merge_sort(0,n-1); cout<<sum<<endl; return 0; }
归并排序: 如 2 4 3 1 先将数据分成 2 , 4, 3, 1,四个数组; 之后结合 2,4 和 3,1 将数组 2,4和 3,1 排序 变为 {2,4} {1,3} 用另外一个数组存储(C
先让 2和1比较 1比较小 储存在C0中 之后2和3比较 C1=2, 4,3比较 C2=3 C3=4;
这个是两个数组 a,b,c将 a,b合并到 c之中
- //将有序数组a[]和b[]合并到c[]中
- void merge(int a[], int n, int b[], int m, int c[])
- {
- int i, j, k;
- i = j = k = 0;
- while (i < n && j < m)
- {
- if (a[i] < b[j])
- c[k++] = a[i++];
- else
- c[k++] = b[j++];
- }
- while (i < n)
- c[k++] = a[i++];
- while (j < m)
- c[k++] = b[j++];
- }
如何将 一个数组 合并到另一个数组之中呢: 加入一个中间 值 mid
之后就是 反复调用函数对整个数组的排序
- //将a的两部分有序数列a[first...mid]和a[mid+1...last]合并
- void merge(int a[], int left(左边), int mid, int right(右边), int c[])
- {
- int i = left, j = mid + 1;
- int m = mid, n = right;
- int k = 0;
- while (i <= m && j <= n)
- {
- if (a[i] <= a[j])
- c[k++] = a[i++];
- else
- c[k++] = a[j++];
- }
- while (i <= m)
- c[k++] = a[i++];
- while (j <= n)
- c[k++] = a[j++];
- for (i = left; i < k; i++) //c数组从左边开始储存
- a[i]=c[i];
- }
可是归并排序 和 你逆序数 有个卵子关系呢? 不要着急 我们回到开头 说到 每次排序都会将小的排到前面 比如 3 1 在排序的时候我们会将 1排在3前面
- void merge_sort(int a[],int first,int last,int c[])
- {
- if(first<last)
- {
- int mid=(first+last)/2;//从中间划分为尽量相等两部分
- merge_sort(a,first,mid,c);//递归调用使左边有序
- merge_sort(a,mid+1,last,c);//递归调用使右边有序
- merge(a,first,mid,last,c);//合并
- }
- }
看到这里还是懵逼啊 这特么怎么算啊 调用函数这么多次 我怎么知道啊? 怎么找 ? 不要着急 我们在来回头看一下 将一个数组合并的程序 咦 然后就发现了这个 语句
这个是什么 是关键啊! 咱们假设这会 a数组 就是 {2.4} {1.3}这两个 来来来 一步一步来 第一步 : 注意else first:2 1比较 发现else c0=1 这个时候我们发现 最小的跑到最前面了对不对 这个时候我们就需要记录了!!! 可是问题又来了 怎么记录呢? 我们发现 如果 a[j] 小于 a[i] 的话 a[j]会小于
- while (i <= m && j <= n)
- {
- if (a[i] <= a[j])
- c[k++] = a[i++];
- else
- c[k++] = a[j++];
- }
a[mid-i] 所有的数 仔细想一下 我们之前已经将 数组排好序了都是按照升序排列 对吧! 所以当 else 的时候 我们会发现 sum需要加上 mid-i+1 (mid是a[i]的最后一个数 所以需要加上1
看到这里我们理解了吗? 就是这样 以上有别的博客的 也有自己总结的~ 写到 一点 省赛刚刚结束 打了铁 发现自己弱的要死 以后稳扎稳打 学一个算法必须学会 ! 不然什么都要忘记! for acm come on!