[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]小的数的个数。求一个序列中所有顺序对的值的和。

格式

输入格式

第一行一个数n,表示序列a中元素的个数。

第二行n个数,第i个数表示a[i]。

输出格式

输出一个数,序列a中所有顺序对的值的和。

样例1

样例输入1

5
1 5 3 4 2

样例输出1

1

限制

每个测试点2s。

提示

对于100%的数据,2<=n<=5000,a[i]<=10^9。

题意

求下式的值:

\[\sum _{j=1} ^n \sum _{i=1}^{j-1} \sum _{k=i+1,a[i]<a[k]<a[j]}^{j-1}1\]

题解

一眼离散化思博题OwO...

每个数对于排在后面且大于它的数的所得到的答案的贡献等于排在它前面且小于它的数的个数.

所以考虑开两个能够快速维护前缀和的数据结构, 这样扫描一遍就可以解决.

两个数据结构一个用于计算贡献一个用于计算最终答案. 

每次扫描到一个数之后在计算最终答案的结构中查询前缀和并累计到最终答案, 然后在计算贡献的结构中查询前缀和并向计算最终答案的结构中累加. 最后在计算贡献的结构中累加上这个数产生的贡献.

参考代码

GitHub

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <iostream>
 5 #include <algorithm>
 6 
 7 const int MAXN=300010;
 8 
 9 #define int long long
10 
11 int n;
12 int* ed;
13 int a[MAXN];
14 int d[MAXN];
15 long long c[MAXN];
16 long long l[MAXN];
17 
18 int Pos(int);
19 int LowBit(int);
20 long long Query(long long*,int);
21 void Add(long long*,int,long long);
22 
23 signed main(){
24     int ans=0;
25     scanf("%lld",&n);
26     for(int i=1;i<=n;i++){
27         scanf("%lld",a+i);
28         d[i]=a[i];
29     }
30     std::sort(d+1,d+1+n);
31     ed=std::unique(d+1,d+1+n);
32     for(int i=1;i<=n;i++){
33         int k=Pos(a[i]);
34         ans+=Query(c,k);
35         Add(c,k,Query(l,k));
36         Add(l,k,1);
37     }
38     printf("%lld\n",ans);
39     return 0;
40 }
41 
42 inline int Pos(int x){
43     return std::lower_bound(d+1,ed,x)-d;
44 }
45 
46 inline void Add(long long* c,int x,long long d){
47     while(x<=n){
48         c[x]+=d;
49         x+=LowBit(x);
50     }
51 }
52 
53 inline long long Query(long long* c,int x){
54     long long ans=0;
55     while(x>0){
56         ans+=c[x];
57         x-=LowBit(x);
58     }
59     return ans;
60 }
61 
62 inline int LowBit(int x){
63     return x&-x;
64 }
Backup

 

posted @ 2017-08-09 15:30  rvalue  阅读(338)  评论(0编辑  收藏  举报