题意:n个数,a1~an(ai<=100000),统计满足条件的三个数的组数。条件是三个数aa,ab,ac,使得a<b<c且ab介于aa和ac之间。
思路:树状数组。我们可以这样考虑,枚举中间的那个数k,中间那个数为k并满足条件的组数等于 在k左边比k小的数的个数乘上在k右边比k大的数的个数,加上 在k右边比k小的数的个数乘上在k左边比k大的数的个数。。这样我们就可以用树状数组来进行统计。先统计一次所有数的情况,再动态统计一次,边计算。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
#define INF 1<<30
#define ll long long
#define max3(a,b,c) max(a,max(b,c))
#define MAXA 100000
using namespace std;
int a[20010];
int c[100010];
int call[100010];
inline int lowbit(int x){
return x&-x;
}
int sum(int end,int* arr){
int re=0;
while(end){
re+=arr[end];
end-=lowbit(end);
}
return re;
}
void add(int pos,int* arr){
while(pos<=MAXA){
arr[pos]++;
pos+=lowbit(pos);
}
}
int main(){
int t;
cin>>t;
while(t--){
memset(c,0,sizeof(c));
memset(call,0,sizeof(call));
memset(a,0,sizeof(a));
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
add(a[i],call);
}
ll ans=0;
for(int i=1;i<=n;i++){
add(a[i],c);
if(i==1||i==n)continue;
ll tmp=sum(a[i]-1,c) * (( n-sum(a[i],call)) - (i-sum(a[i],c)) ) ;
ans+=tmp;
tmp=(i-sum(a[i],c)) * (sum(a[i]-1,call) - sum(a[i]-1,c));
ans+=tmp;
}
cout<<ans<<endl;
}
return 0;
}
本文介绍了一种利用树状数组解决特定三元组计数问题的方法。通过枚举中间元素,统计左侧小于该元素及右侧大于该元素的数量组合,实现了高效计算。文章提供了完整的代码实现。
140

被折叠的 条评论
为什么被折叠?



