题目:http://codeforces.com/problemset/problem/61/E
题意:若一个组数下标 i<j<k以及ai>aj>ak 则为一个弱点,计算一组数据中有几个弱点。
思路:1)使用树状数组,从左到右扫描所有的数,令数组a 表示目前为止 已经考虑过的所有的数num,是否存在一个,存在则a[j]=1,不存在则a[j]=0。在计算一个数前面比它的大 数和后面比它小的数可以计算前缀和和后缀和。
2) 先从前往后搜索数组,使用数组a1记录每一个数前面比它大的的数的个数,使用数组a2记录每一个数后面比它小的数的个数。当以数n1为中间数是有a1*a2个弱点。
3)由于数的大小为1 ≤ ai ≤ 109,无法开这么大的数组来记录数是否存在。使用数的离散化,将数列排序,使用数组的下标代表代表数的相对大小。使用二分查找lower_bound来查找原数组n1在已排序数组num在的下标。
*注意:树状数组不能从0开始存!所以可以将所有的数组的开头下标设为1。
CODE;
#include <iostream>
#include <stdio.h>
#include <algorithm>
const int N=1000005;
using namespace std;
int n1[N],num[N],a[N],c[N];
int T;
int lowbit(int xx)
{
return xx&-xx; //树状数组不能从0开始存
}
void add(int x,int d)
{
while(x<=T)
{
c[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int ret=0;
while(x>0)
{
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
bool cmp(int a,int b)
{
return a<b;
}
long long a1[N],a2[N];
int main()
{
//freopen("in.in","r",stdin);
while(~scanf("%d",&T))
{
fill(a,a+T+1,0);
fill(c,c+T+1,0);
for(int i=1;i<=T;i++)
{
scanf("%d",&n1[i]);
num[i]=n1[i];
}
sort(num+1,num+T+1,cmp);
long long ans=0;
for(int i=1;i<=T;i++)
{
int k=lower_bound(num,num+T+1,n1[i])-num;
a[k]=1;
add(k,1);
a1[i]=sum(T)-sum(k);
}
fill(a,a+T+1,0);
fill(c,c+T+1,0);
for(int i=T;i>=1;i--)
{
int k=lower_bound(num,num+T+1,n1[i])-num;
a[k]=1;
add(k,1);
a2[i]=sum(k-1);
}
for(int i=1;i<=T;i++)
ans+=a1[i]*a2[i];
printf("%I64d\n",ans);
}
return 0;
}