Sequence II
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1002 Accepted Submission(s): 408
Problem Description
Long
long ago, there is a sequence A with length n. All numbers in this
sequence is no smaller than 1 and no bigger than n, and all numbers are
different in this sequence.
Please calculate how many quad (a,b,c,d) satisfy:
1. 1≤a<b<c<d
2. Aa<Ab
3. Ac<Ad
Please calculate how many quad (a,b,c,d) satisfy:
1. 1≤a<b<c<d
2. Aa<Ab
3. Ac<Ad
Input
The first line contains a single integer T, indicating the number of test cases.
Each test case begins with a line contains an integer n.
The next line follows n integers A1,A2,…,An.
[Technical Specification]
1 <= T <= 100
1 <= n <= 50000
1 <= Ai <= n
Each test case begins with a line contains an integer n.
The next line follows n integers A1,A2,…,An.
[Technical Specification]
1 <= T <= 100
1 <= n <= 50000
1 <= Ai <= n
Output
For each case output one line contains a integer,the number of quad.
Sample Input
1
5
1 3 2 4 5
Sample Output
4
Source
题意:找出一个长度为n的串里面有多少数字满足 Aa<Ab,Ac<Ad,a<b<c<d (a,b,c,d是下标)
题解:做过这个题之后一看就知道是树状数组统计了,我的想法是对每个 b 进行统计,首先是对b前面的数字进行统计,统计有多少个比它小的,这里可以利用树状数组的逆序模型进行统计。然后对于b后面的数字,我们可以统计有多少对 (c,d),这里的话从n-1对每个数进行统计比它大的有多少,然后如果要统计 b 后面有多少个比它大的数对,那么我们就可以利用保存后缀和的方式存下来就OK,最后里用乘法原理统计即可。l,r数组一定记得开_int64 ,不然会溢出。
解释一下这里的后缀,比如说 1 2 3 4 5
先统计 5 ,没有比他大的,所以r[5] = 0
然后是 4 ,5 比他大,所以 r[4] = 1
然后是 3 , 4 5比他大,所以 r[3]=2,加上后面已经出现的r[4],r[3]=r[3]+r[4] = 3
然后是 2 ,r[2]:(2,3)(2,4)(2,5) 加上 (3,4),(3,5),(4,5),所以r[2] = 6
最后是 1 , r[1]:(1,2)(1,3)(1,4)(1,5),加上r[3] 所以 r[1] = 10
我们是以 Ab 为基准的,所以每次统计的是 b 之前比比他小的,以及他后面所包含的二元组.所以每次的结果是 L[b]*R[b+1]
#include<stdio.h> #include<iostream> #include<string.h> #include <stdlib.h> #include<math.h> #include<algorithm> using namespace std; typedef long long LL; const int N = 50005; int n; int c[N],a[N]; LL l[N],r[N]; int lowbit(int x) { return x&-x; } void update(int idx,int v) { for(int i=idx; i<=n; i+=lowbit(i)) { c[i]+=v; } } int getsum(int idx) { int sum = 0; for(int i=idx; i>0; i-=lowbit(i)) { sum+=c[i]; } return sum; } int main() { int tcase; scanf("%d",&tcase); while(tcase--) { memset(c,0,sizeof(c)); memset(l,0,sizeof(l)); scanf("%d",&n); int cnt = 0; for(int i=1; i<=n; i++) { scanf("%d",&a[i]); update(a[i],1); l[i] = getsum(a[i]-1); ///a[i]之前小于a[i]的数 } memset(c,0,sizeof(c)); memset(r,0,sizeof(r)); for(int i=n; i>=1; i--) { update(a[i],1); r[i]=n-i-getsum(a[i]-1);///统计每个数后面比它大的 r[i]+=r[i+1]; ///记录后缀和 } LL ans = 0; for(int i=2;i<n-1;i++){ ans+=l[i]*r[i+1]; } printf("%lld ",ans); } return 0; }