Erwin
最近对一种叫thair
的东西巨感兴趣……
在含有 个整数的序列 中,
三个数被称作thair
当且仅当
且
。
求一个序列中thair
的个数。
像这种,考虑三个数之间的关系的题目,我们可以从中间元素入手。
记 表示第 个数左边小于它的数的个数, 表示第 个数右边大于它的数的个数。不难发现,总答案 满足:
既然如此,我们就可以用 来求出 和 。总的时间复杂度为 。
需要注意的是,因为 的取值范围太大,所以我们先要对它进行 。
const int N=30100;
struct node{
int sub,num,number;
}a[N];int n,m,c[2][N];
inline bool cmp1(node a,node b){
return a.num<b.num;
}
inline bool cmp2(node a,node b){
return a.sub<b.sub;
}
inline int F(int x){
return x&(-x);
}//相当于树状数组的lowbit函数
typedef long long ll;
inline void updata(int x,int p){
for(;x<=m;x+=F(x)) c[p][x]++;
}//树状数组的修改操作
inline int query(int x,int p){
register int cnt=0;
for(;x;x-=F(x))
cnt+=c[p][x];
return cnt;
}//树状数组的求前缀和操作
int Left[N],Right[N];ll ans;
int main(){
freopen("t1.in","r",stdin);
scanf("%d",&n);ans=0ll;
for(int i=1;i<=n;i++){
scanf("%d",&a[i].num);
a[i].sub=i;//保存该数的下标
}
// 从第33行到第40行为离散化操作
sort(a+1,a+n+1,cmp1);
a[1].number=1;
for(int i=2;i<=n;i++)
if (a[i].num!=a[i-1].num)
a[i].number=a[i-1].number+1;
else a[i].number=a[i-1].number;
m=a[n].number;
sort(a+1,a+n+1,cmp2);
for(int i=1;i<=n;i++){
updata(a[i].number,0);
Left[i]=query(a[i].number-1,0);
}//求Left数组
for(int i=n;i;i--){
updata(m-a[i].number+1,1);
Right[i]=query(m-a[i].number,1);
}//求Right数组,通过减法把求大于一个数的数的个数操作转化为了求小于该数的数的个数的操作
for(int i=1;i<=n;i++)//计算ans,注意中间结果不要溢出
ans+=(ll)Left[i]*Right[i];
printf("%lld",ans);
return 0;
}