归并求逆序对
归并求逆序对 是分治的一个经典例子。
简述算法:
利用归并把序列对半分,在一般的归并过程中,我们在前后两部分各设两个指针,按照大小顺序合并成一个序列。
我们要做的就是在这个过程中记录逆序对个数,什么情况下会有逆序对呢?
无非是在前面的数比在后面的数大(翻译过来:在前半部分的数比在后半部分的数大)
设前半部分的指针为t1,后半部分的指针为t2
如果a[t1] > a[t2],那么t1~mid的元素一定都比t2大,一定都可以与t2形成逆序对:ans+= (mid- t1+ 1)+1
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 5 using namespace std; 6 7 const int N=100010; 8 int a[N],b[N],n,ans=0; 9 10 void merge(int l,int r) 11 { 12 if (l==r) return; 13 int mid=(l+r)>>1; 14 merge(l,mid); 15 merge(mid+1,r); 16 int t1=l; 17 int t2=mid+1; 18 for (int i=l;i<=r;i++) 19 { 20 if ((t1<=mid&&a[t1]<=a[t2])||t2>r) { 21 b[i]=a[t1]; 22 t1++; 23 } 24 else 25 { 26 b[i]=a[t2]; 27 ans+=(mid-t1+1); 28 t2++; 29 } 30 } 31 for (int i=l;i<=r;i++) a[i]=b[i]; 32 } 33 34 int main() 35 { 36 scanf("%d",&n); 37 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 38 merge(1,n); 39 printf("%d",ans); 40 return 0; 41 }
end;