PS:思维还是太弱了,计算方法太神奇!
题意:就是找四个不同的数,a<b,c>d.算种数
分析:简化一下问题,如果单纯求a<b和c>d,树状数组求逆序对即可。但是这里a,b,c,d不能相同。那么就考虑一下怎么去重。枚举一个数,他左边比他小的数就可以当做a,相当于他是b。他左边比他大的数就是c,相当于他是d。同理,看右边是一样的。那样把左边所有小于当前数的数求和,大于的一样。乘积是什么。就是算可以重复的总种数。这时候的重点就是考虑去重。首先就按我上面说的那个例子,就相当于重复计算了b==d,这时候要去掉它。这时候就要去掉它的左小和左大的乘积,因为有a<b,c>d,所以a!=c,不会多减。同理去掉其他三种情况即可。见代码详解。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
int a[50005],b[50005];
int bit[50005];
int n,m;
int query(int i)
{
int ans=0;
while(i)
{
ans+=bit[i];
i-=(i&-i);
}
return ans;
}
void add(int i)
{
while(i<=m)
{
bit[i]++;
i+=i&(-i);
}
}
int lmin[50005],lmax[50005],rmin[50005],rmax[50005];
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n);m=unique(b+1,b+1+n)-(b+1);
for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+m+1,a[i])-b;//离散化,可能有重复。
memset(bit,0,sizeof(bit));
for(int i=1;i<=n;i++)
{
lmin[i]=query(a[i]-1);
lmax[i]=query(m)-query(a[i]);
//printf("%d %d\n",lmin[i],lmax[i]);
add(a[i]);
}
memset(bit,0,sizeof(bit));
for(int i=n;i>0;i--)
{
rmin[i]=query(a[i]-1);
rmax[i]=query(m)-query(a[i]);
add(a[i]);
}
ll ans=0,x=0,y=0;
for(int i=1;i<=n;i++)//总的
{
x+=rmin[i];
y+=rmax[i];
}
ans=x*y;
//b==d
for(int i=1;i<=n;i++)
{
x=lmin[i];
y=rmin[i];
ans-=x*y;
}
//a==d
for(int i=1;i<=n;i++)
{
x=lmax[i];
y=rmax[i];
ans-=x*y;
}
//b==c
for(int i=1;i<=n;i++)
{
x=lmin[i];
y=lmax[i];
ans-=x*y;
}
//a==c
for(int i=1;i<=n;i++)
{
x=rmin[i];
y=rmax[i];
ans-=x*y;
}
printf("%lld\n",ans);
}
return 0;
}