算法复习——归并排序

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

归并排序跟堆排序一样可以稳定把时间压在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.





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值