算法复习——归并排序

来源:互联网 发布:python格式化输出数字 编辑:程序博客网 时间:2024/05/17 07:08

其实这是那篇《二分法》的延伸版本……

归并排序跟堆排序一样可以稳定把时间压在O(log n),因为它始终会把区间二分处理,到了不能再二分时便开始合并区间。

接下来看一道题:codevs3286

这一道题就是典型的逆序对。要使两列火柴距离最小,明显就要让在两序列中相对大小相同的火柴在同一位置

于是我们对两列火柴进行排序,排序后用一个pos[a[i].p]=b[i].p表示第i个位置应放哪一根b列中的火柴,然后就可以对pos作归并排序求逆序对啦

代码如下:

type rec=record     num,p:longint;     end;     arr=array[1..100000]of rec;var a,b:arr;    pos,tmp:array[1..100000]of longint;    n,i:longint;    ans:qword;procedure merge(left,p,right:longint);var   i,j,k:longint;begin   i:=left; j:=p+1; k:=left;   while (i<=p) and (j<=right) do   begin     if pos[i]<=pos[j] then     begin       tmp[k]:=pos[i];       inc(i);     end     else     begin       tmp[k]:=pos[j];       inc(j);       ans:=(ans+p-i+1)mod 99999997;     end;     inc(k);   end;   while i<=p do   begin  tmp[k]:=pos[i];inc(i);inc(k);  end;   while j<=right do   begin  tmp[k]:=pos[j];inc(j);inc(k);  end;   for i:=left to right do      pos[i]:=tmp[i];end;procedure mergesort(left,right:longint);var mid:longint;begin  if left<right then  begin    mid:=(left+right) div 2;    mergesort(left,mid);    mergesort(mid+1,right);    merge(left,mid,right);  end;end;procedure qs(l,r:longint;var p:arr);var i,j,mid:longint;    t:rec;begin  i:=l;  j:=r;  mid:=p[(i+j)div 2].num;  repeat    while p[i].num<mid do inc(i);    while p[j].num>mid do dec(j);    if i<=j then    begin      t:=p[i];      p[i]:=p[j];      p[j]:=t;      inc(i);      dec(j);    end;  until i>j;  if l<j then qs(l,j,p);  if i<r then qs(i,r,p);end;begin  readln(n);  for i:=1 to n do  begin    read(a[i].num);    a[i].p:=i;  end;  for i:=1 to n do  begin    read(b[i].num);    b[i].p:=i;  end;  qs(1,n,a);  qs(1,n,b);  for i:=1 to n do  pos[a[i].p]:=b[i].p;  mergesort(1,n);  writeln(ans mod 99999997);end.





0 0
原创粉丝点击