这道题我也不知道怎么了,改着改着就AC了。。。。。。(然而自己看不懂自己的代码)
但在我仔细思考后就想通了^ _ ^ 233。
不是有三个数吗,那就吧当前枚举的数当做三个数中的第二个,先找比它小的数有几个,再找比它大的数有几个,分别用mi[ ]和ma [ ]记录下来,
最终答案就是ans+=mi[i]*ma[i];
由此,我们想到了用树状数组求比它大和比它小的数有多少个——即逆序队。
先由小到大排序,求比它小的数个数,再从大到小排序,求比它大的数个数。
Code(详见代码):
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=30005;
long long map[N],f[N],n,mi[N],ma[N],ans=0;
struct node
{
int pos,val;
}a[N];
bool cmp(node x,node b)
{
return x.val<b.val;
}
bool cmp2(node x,node b)
{
return x.val>b.val;
}
void add(long long k,int w)
{
while(k<=n)
{
f[k]+=w;
k+=k&-k;
}
}
long long query(long long k)
{
long long sum=0;
while(k>=1)
{
sum+=f[k];
k-=k&-k;
}
return sum;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i].val);a[i].pos=i;
}
sort(a+1,a+1+n,cmp);//从小到大牌
for(int i=1;i<=n;i++)//离散化 加 去重
{
if(a[i].val==a[i-1].val) map[a[i].pos]=map[a[i-1].pos];
else map[a[i].pos]=i;
}
for(int i=1;i<=n;i++)
{
mi[i]=query(map[i]-1);
add(map[i],1);
}
sort(a+1,a+1+n,cmp2);//从大到小排
memset(f,0,sizeof(f));//初始化f数组
for(int i=1;i<=n;i++)
{
if(a[i].val==a[i-1].val)map[a[i].pos]=map[a[i-1].pos];
else map[a[i].pos]=i;
}
for(int i=n;i>=1;i--)
{
ma[i]=query(map[i]-1);//要去掉本身,so -1 ,还有请注意我和楼下写的不一样,所以我不是n-map[i]
add(map[i],1);
}
for(int i=1;i<=n;i++)ans+=mi[i]*ma[i];
printf("%lld",ans);
}