给你n个数(1<=n<=1e6),定义 f (l , r , x)为区间 [ l , r ] 内与 x
相等的数的个数。问你有多少对 i , j (i < j)使得 f (1 , i , a[ i ]) > f (j , n , a[ j ])。
问1到i区间有多少数和a[ i ]相等显然可以预处理出来,得 pre[ i ] == f (1 , i , a[ i ])
同理得suf[ j ] == f (j , n , a[ j ])。在满足偏序关系 i < j 时又要满足偏序关系
f (1 , i , a[ i ]) > f (j , n , a[ j ]) (pre[ i ] > suf [ j ] ),可以用树状数组高效实现。
树状数组的更新会自动满足 i < j的条件, 现枚举 i ,树状数组里存的是suf [ j ],
每次查询比pre[ i ] 小的suf [ j ]的个数,加到ans里就好了。(这道题目也可以用线段树做)。
注意树状数组里存的值可能会超过 int 。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<cstring>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
const int MAXN=1000000+5;
const ll INF=1e9;
const ll mod=1e9+7;
int a[MAXN];
int suf[MAXN],pre[MAXN];
ll bit[MAXN];
int n;
ll sum(int x){
ll ans=0;
while(x>0){
ans+=bit[ x ];
x-=x&-x;
}
return ans;
}
void add(int i,ll x){
while( i<=n ){
bit[i]+=x;
i+=i&-i;
}
}
int main()
{
//freopen("A-large.in","r",stdin);
//freopen("A-large.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
map<int,int > mp;
for(int i=1;i<=n;i++){
mp[ a[i] ]++;
pre[i]=mp[ a[i] ];
}
mp.clear();
for(int i=n;i>=1;i--){
mp[a[i]]++;
suf[i]=mp[ a[i] ];
}
memset(bit,0,sizeof(bit));
ll ans=0;
for(int i=n;i>=1;i--){
ans+=sum( pre[i]-1 );
add( suf[i],1 );
}
printf("%I64d\n",ans);
return 0;
}