分治 求逆序对数

SSL 1198
题目描述
先给出逆序对的定义,对于一个给定的数列{An},如果有iAj,则称(i,j)为一逆序对.
求给出一个数列,求出这个数列包含多少个逆序对?
(说明一下啊,是从小到大逆序的)

题目分析
分治很难看出来,不过实质是用归并排序。
归并时,若有一个数与前面这个数逆序的话,那么毫无疑问,这个区间后面的数肯定都与它逆序。
原理化成代码就是:
if a[i],a[j]逆序时 then
记录变量:=记录变量+1+mid-位于前面的指针;
就这么简单

代码如下

var
  n,i,s:longint;
  a:array[1..10000]of longint;
procedure m(l,mid,h:longint);
var
  i,j,k:longint;
  b:array[1..10000]of longint;
begin
  i:=l;j:=mid+1;fillchar(b,sizeof(b),#0);
  k:=0;
  while (i<=mid)and(j<=h) do
   if a[i]>a[j] then
    begin
      s:=s+mid+1-i;
      inc(k);
      b[k]:=a[j];
      inc(j);
    end
   else
    begin
      inc(k);
      b[k]:=a[i];
      inc(i);
    end;
  for i:=i to mid do begin inc(k);b[k]:=a[i]; end;
  for i:=j to h do begin inc(k);b[k]:=a[i]; end;
  for i:=l to h do a[i]:=b[i-l+1];
end;

procedure ms(l,h:longint);
var
  mid:longint;
begin
  if l<h then
   begin
     mid:=(l+h)div 2;
     ms(l,mid);
     ms(mid+1,h);
     m(l,mid,h);
   end;
end;

begin
  readln(n);
  for i:=1 to n do read(a[i]);
  ms(1,n);
  writeln(s);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值