原题地址:
http://acm.hdu.edu.cn/showproblem.php?pid=5147
Sequence II
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 652 Accepted Submission(s): 164
问题描述
很久很久以前,有一个长度为n的数列A,数列中的每个数都不小于1且不大于n,且数列中不存在两个相同的数. 请统计有多少四元组(a,b,c,d)满足: 1. 1≤a<b<c<d≤n 2. Aa<Ab 3. Ac<Ad
输入说明
第一行输入一个整数T,表示有T组测试数据.
每组测试数据第一行包含一个整数n,第二行包含n个整数.
数据范围
1 <= T <= 100
1 <= n <= 50000
1 <=
Ai
<= n
输出说明
对于每组测试数据,输出一个整数表示四元组的数量.
输入样例
1 5 1 3 2 4 5
输出样例
4
思路:
要统计四元组的数量我们可以通过枚举c,然后统计区间[1,c-1]有多少二元组(a,b)满足a < b且 Aa<Ab ,以及统计出区间[c+1,n]有多少d满足 Ac<Ad ,根据乘法原理,把这两项乘起来就可以统计到答案里了. 然后我们来处理子问题:区间[1,c-1]内有多少二元组(a,b).那么我们可以枚举b,然后统计区间[1,b-1]内有多少a满足 Aa<Ab ,那么这个可以通过用树状数组询问前缀和来实现. 时间复杂度是O(nlogn). //本段为官方题解
代码:
#include "stdio.h" #include "iostream" #include "string.h" #include "algorithm" using namespace std; int num[500050],c[500050],cr[500050],bl[500050],n,T; long long ans,sum,ssum[500050]; int lowbit(int x) { return x&(-x); } void s(int i) { if(i>0) { sum+=c[i]; s(i-lowbit(i)); } } void update(int i,int val) { while(i<=n) { c[i] += val; i += lowbit(i); } } long long get_sum(int i) { sum=0; s(i); return sum; } int main() { scanf("%d",&T); while(T--) { ans=0; memset(cr,0,sizeof(cr)); memset(bl,0,sizeof(bl)); memset(c,0,sizeof(c)); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); } for(int i=1;i<=n;i++) { bl[i]=get_sum(num[i]); update(num[i],1); } memset(c,0,sizeof(c)); for(int i=1;i<=n;i++) num[i]=n+1-num[i]; for(int i=n;i>0;i--) { cr[i]=get_sum(num[i]); update(num[i],1); } memset(c,0,sizeof(c)); for(int i=1;i<=n;i++) { update(i,cr[i]); } for(int i=2;i<n-1;i++) { ans+=(get_sum(n)-get_sum(i))*bl[i]; } printf("%I64d\n",ans); } return 0; }
PS:第一次手写树状数组~A了很开心啦~虽然是在比赛结束以后,学到知识就好了~