题目链接:cf 459d
用f(l,r,x)表示l~r区间中ai=x的个数 求i,j对数和使得f(1,i,ai)>f(j,n,aj)
预处理出每个点分别在左右区间时的值,然后利用树状数组求解
/******************************************************
* File Name: d.cpp
* Author: kojimai
* Creater Time:2014年08月16日 星期六 15时22分54秒
******************************************************/
/*
*用f(l,r,x)表示在l~r的区间内ai=x的个数 求i,j的对数满足f(1,i,ai)>f(j,n,aj)
*用树状数组表示出从x到n中1~f(1,x,ax)的总和即可
*/
#include<map>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 1000005
int a[FFF],lef[FFF],rig[FFF];
map<int,int> l,r;//l表示从左开始该位置的数出现的次数 r表示到末尾结束该数出现的次数
int n;
int sum[FFF];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int num)
{
while(x<=n)
{
sum[x]+=num;
x+=lowbit(x);
}
return;
}
int getsum(int x)
{
int ret=0;
while(x>0)
{
ret+=sum[x];
x-=lowbit(x);
}
return ret;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
l[a[i]]++;
lef[i]=l[a[i]];//f(1,i,ai)
}
for(int i=n;i>=1;i--)
{
r[a[i]]++;
rig[i]=r[a[i]];//f(j,n,aj)
}
for(int i=n;i>=1;i--)
update(rig[i],1);//把所有都放在右区间
long long ans=0;
for(int i=1;i<=n;i++)
{
update(rig[i],-1);//将该点放在左区间
ans+=getsum(lef[i]-1);//统计1~f(1,i,ai)-1的总和
}
cout<<ans<<endl;
return 0;
}