您的位置:首页 > 其它

算法复习——归并排序

2016-04-19 14:00 225 查看
其实这是那篇《二分法》的延伸版本……

归并排序跟堆排序一样可以稳定把时间压在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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: