a[i]代表第i个点(i,b[i]),
若 1<=i<j<k<=n && a[i]>a[j]<a[k] 则为“尖刀”;
若 1<=i<j<k<=n && a[i]<a[j]>a[k] 则为“铁锹”。
对于1~n中的每个i,求出它前面的比它大的数的个数m,求出它后面比它大的数的个数n,m*n即为以第i个数为尖尖的“尖刀”的数目,1~n累加即为“尖刀”的总数。同理,求出它前面的比它小的数的个数m,求出它后面比它小的数的个数n,m*n即为以第i个数为尖尖的“铁锹”的数目,1~n累加即为“铁锹”的总数。我们用树状数组来求每个数 之前/之后 比它 大/小 的数字的个数,来求得答案。
代码如下:
#include<iostream>
using namespace std;
const int N=200005;
int a[N]={0},b[N]={0},n=0; //a是输入的数据,b是树形数组,用来计算当前数 之前/之后 比当前数 大/小 的数有多少个
long long int b1[N]={0},b2[N]={0}; //b1[i]表示以第i个为尖尖的“尖刀”有多少个,b2[i]表示以第i个为尖尖的“铁锹”有多少个
//单点修改(加1)和区间查询
void add(int x){
for(int i=x;i<=n;i+=(i&(-i)))++b[i];
}
int sum(int x){
int res=0;
for(int i=x;i;i-=(i&(-i)))res+=b[i];
return res;
}
int main(){
std::ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<=n;++i){
add(a[i]);
b1[i]=sum(n)-sum(a[i]); //计算i之前的数中比它大的有多少个
b2[i]=sum(a[i]-1); //计算i之前的数中比它小的有多少个
}
for(int i=1;i<=n;++i)b[i]=0;
long long int ans1=0,ans2=0;
for(int i=n;i>0;--i){
add(a[i]);
b1[i]*=(sum(n)-sum(a[i])); //乘上i之后的数中比它大的数字的个数
b2[i]*=(sum(a[i]-1)); //乘上i之后的数中比它小的数字的个数
ans1+=b1[i]; //累加至答案中
ans2+=b2[i];
}
cout<<ans1<<" "<<ans2<<endl;
return 0;
}