noip2013火柴排队

最小交换次数即求逆序对数。

但应当是某一个数组中每个元素目标位置的新数组的逆序对数(这样才符合“交换”)

求逆序对可以用树状数组O(3nlogn)

program march;
var a,b,c,m,key:array[1..100000]of longint;
     i,n:longint;
ans:int64;
function lowbit(x:longint):longint;
begin
 lowbit:=x and (-x);
end;
procedure qsort(x,y:longint);
var i,j,mid,t:longint;
begin
 i:=x;j:=y;
 mid:=a[(x+y) div 2];
 repeat  
  while a[i]<mid do i:=i+1;
  while a[j]>mid  do j:=j-1;
  if i<=j then 
   begin
    t:=a[i];a[i]:=a[j];a[j]:=t;
t:=m[i];m[i]:=m[j];m[j]:=t;
i:=i+1;j:=j-1;
   end;
 until i>j;
 if x<j then qsort(x,j);
 if i<y then qsort(i,y);
end;
procedure qsort1(x,y:longint);
var i,j,t,mid:longint;
begin
 i:=x;j:=y;
 mid:=b[(x+y) div 2];
 repeat 
  while b[i]<mid do i:=i+1;
  while b[j]>mid do j:=j-1;
  if i<=j then 
   begin
    t:=b[i];b[i]:=b[j];b[j]:=t;
t:=m[i];m[i]:=m[j];m[j]:=t;
i:=i+1;j:=j-1;
   end;
 until i>j;
 if i<y then qsort1(i,y);
 if x<j then qsort1(x,j);
end;
procedure updata(x,n:longint);
begin
 while x<=n do
  begin
    c[x]:=c[x]+1;
x:=x+lowbit(x);
  end;
end;
function getsum(x:longint):longint;
var s:longint;
begin
 s:=0;
 while x>0 do
  begin
   s:=s+c[x];
   x:=x-lowbit(x);
  end;
 getsum:=s;
end;
begin
 read(n);
 for i:=1 to n do begin m[i]:=i;read(a[i]);end;
 qsort(1,n);
 for i:=1 to n do a[m[i]]:=i;//对a离散化
 for i:=1 to n do begin read(b[i]);m[i]:=i;end;
 qsort1(1,n);

 for i:=1 to n do b[m[i]]:=i;//对b离散化

//确定b目标位置

 for i:=1 to n do key[a[i]]:=i;

 for i:=1 to n do b[i]:=key[b[i]];

 //求逆序对数

 for i:=1 to n do
  begin 
   updata(b[i],n);//c[]以元素大小为下标
   ans:=(ans+i-getsum(b[i])) mod 99999997;
  end;
 write(ans);
end.
 

这题为什么不可以先将a、b按a从小到大排序,再将b离散化再求b的逆序对呢?因为这样破坏了移动顺序,答案有问题。


你可能感兴趣的:(树状数组,逆序对)