vijos 1768顺序对的值

题目描述:

给定一个序列a,a中任意两个元素都不等。如果i<j,且a[i]<a[j],则我们称a[i],a[j]为一个顺序对,这个顺序对的值是指a[i+1],a[i+2]…….a[j-1]中比a[i]大,且比a[j]小的数的个数。求一个序列中所有顺序对的值的和。

这题的想法是看每个a[k]对一对a[i],a[j]的贡献,如果a[k]前面有sum1个数比它小,后面有sum2个数比它大,那么ans加上sum1*sum2

朴素算法O(n^2)

program t;
var n,i,j,s2,s1:longint;
    a:array[1..5000]of longint;
    ans:int64;
begin
 read(n);
 for i:=1 to n do
  read(a[i]);
 for i:=1 to n do
  begin
   s1:=0;s2:=0;
   for j:=1 to i-1 do if a[j]<a[i] then s1:=s1+1;
   for j:=i+1 to n do if a[j]>a[i] then s2:=s2+1;
   ans:=ans+s1*s2;
  end;
 write(ans);
end.         
更快的是用树状数组求sum1和sum2

program shuzhuang;
var a,b,c,d,c1,d1:array[1..5002]of longint;
    n,i:longint;
    ans:int64;//n<=5000,最大可能为5000*2500*2500,longint不够
procedure qsort(x,y:longint);
var i,j,t,mid: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:=b[i];b[i]:=b[j];b[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;
function lowbit(x:longint):longint;
begin
 lowbit:=x and (-x);
end;

procedure updata(x,val:longint);
var j:longint;
begin
 j:=x;
 while j<=n do
  begin
   c[j]:=c[j]+val;
   j:=j+lowbit(j);
  end;
end;
procedure updata1(x,val:longint);
var j:longint;
begin
 j:=x;
 while j<=n do
  begin
   d[j]:=d[j]+val;
   j:=j+lowbit(j);
  end;
end;
function sum(x:longint):longint;
var j:longint;
begin
 j:=x;
 sum:=0;
 while j>0 do
  begin
   sum:=sum+c[j];
   j:=j-lowbit(j);
  end;
end;
function sum1(x:longint):longint;
var j:longint;
begin
 j:=x;
 sum1:=0;
 while j>0 do
  begin
   sum1:=sum1+d[j];
   j:=j-lowbit(j);
  end;
end;
begin
 read(n);
 for i:=1 to n do
  begin
   read(a[i]);
   b[i]:=i;
  end;
 qsort(1,n);
 for i:=1 to n do
  c1[b[i]]:=i; //离散化,因为以数字大小为下标统计
 //树状数组,统计每个数前面有几个数比它小,后面有几个数比它大
 for i:=1 to n do
  begin
   updata1(c1[n-i+1],1);
   d1[i]:=i-sum1(c1[n-i+1]);
  end;
 for i:=1 to n do
  begin
   updata(c1[i],1);
   ans:=ans+(sum(c1[i])-1)*d1[n-i+1];//更新和累加同步进行
  end;
 write(ans);
end.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值