Thair数 树状数组

题目:

Erwin最近对一种叫"thair"的东西巨感兴趣。。。

在含有n个整数的序列a1,a2......an中,

三个数被称作"thair"当且仅当i<j<k且ai<aj<ak

求一个序列中"thair"的个数。

 

Input (thair.in)

开始一个正整数n,

以后n个数a1~an

 

Output (thair.out)

"thair"的个数

 

Sample

Input

Output

4

2 1 3 4

2

5

1 2 2 3 4

7

 

对样例2的说明:

7个"thair"分别是

1 2 3

1 2 4

1 2 3

1 2 4

1 3 4

2 3 4

2 3 4

 

约定

30%的数据n<=100

60%的数据n<=2000

100%的数据n<=30000

大数据随机生成

0<=a[i]<=maxlongint

 

 

首先分析题目,对于任意一个数a[i],它前面的每一个数都可以与后面所有比a[i]大的数形成Thair数,记第i个数前面比它小的数的个数为b[i],后面比它小的数的个数为c[i],那么最后的答案就是Σ(b[i] * c[i])。至于统计个数,由于n到30000,O(n^2)肯定不可行,所以我们用个树状数组就可以降低时间复杂度。而且由于要用到树状数组,但a[i]可能很大,在做之前要先将其离散化。下面是代码

  1 //By Neil
  2 program  Thair;
  3 const
  4     maxN                        =30000 + 100;
  5 var
  6     bit                         :array[0..maxN] of longint;
  7     i,j,k,l,m,n                 :longint;
  8     a,b,c                       :array[0..maxN] of longint;
  9     num,p                       :array[0..maxN] of longint;
 10     tot                         :longint;
 11     ans                :int64;
 12 
 13 procedure  swap(var x,y:longint);
 14 var
 15     tmp                         :longint;
 16 begin
 17     tmp := x;
 18     x := y;
 19     y := tmp;
 20 end;
 21 
 22 procedure  qs(l,r:longint);
 23 var
 24     i,j,k                       :longint;
 25 begin
 26   i := l;
 27   j := r;
 28   k := a[(i + j) div 2];
 29   repeat
 30     while a[i] < k do inc(i);
 31     while a[j] > k do dec(j);
 32     if i <= j then
 33       begin
 34         swap(a[i],a[j]);
 35         swap(num[i],num[j]);
 36         inc(i);
 37         dec(j);
 38       end;
 39   until (i > j);
 40   if i < r then qs(i,r);
 41   if l < j then qs(l,j);
 42 end;
 43 
 44 procedure  add(x :longint);
 45 begin
 46     while (x <= maxN) do
 47       begin
 48         inc(bit[x]);
 49         inc(x,x and (-x));
 50       end;
 51 end;
 52 
 53 function  ask(x :longint):longint;
 54 var
 55     ret                         :longint;
 56 begin
 57     ret := 0;
 58     while (x > 0) do
 59       begin
 60         inc(ret,bit[x]);
 61         dec(x,x and (-x));
 62       end;
 63     exit(ret);
 64 end;
 65 
 66 procedure  init;
 67 begin
 68     read(n);
 69     for i := 1 to n do
 70       begin
 71         read(a[i]);
 72         num[i] := i;
 73       end;
 74     qs(1,n);
 75     a[0] := - maxlongint;
 76     tot := 0;
 77     for i := 1 to n do
 78         if a[i] > a[i - 1] then
 79           begin
 80             inc(tot);
 81             c[num[i]] := tot;
 82           end
 83         else
 84             c[num[i]] := tot;
 85 end;
 86 
 87 procedure  main;
 88 begin
 89   fillchar(a,sizeof(a),0);
 90   for i := 1 to n do
 91     begin
 92         inc(a[i],ask(c[i] - 1));
 93         add(c[i]);
 94     end;
 95   fillchar(bit,sizeof(bit),0);
 96   for i := n downto 1 do
 97     begin
 98         inc(b[i],n - i - ask(c[i]));
 99         add(c[i]);
100     end;
101   for i := 1 to n do inc(ans,a[i] * b[i]);
102   writeln(ans);
103 end;
104 
105 begin
106     assign(input,'Thair.in');
107     reset(input);
108     assign(output,'Thair.out');
109     rewrite(output);
110     init;
111     main;
112     close(input);
113     close(output);
114 end.

 

 

转载于:https://www.cnblogs.com/JohnNeil/p/3699442.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值