题意:给出n个数ai,定义f(l,r,x)为区间[l,r]中,与x相等的数的个数,求有多少对i,j,满足1<=i < j <=n,f(1,i,ai) > f(j,n,aj)。
思路:大胆暴力搞就好了。首先要预处理出来两个数组,一个是f[i],表示前i个数中,与a[i]相等的数的个数,一个是g[i],表示i~n中,与a[i]相等的数的个数。处理出来,从后向前扫,那么问题就变成了,对于当前扫到的i,有多少个g[j]小于f[i],对于这个,将g[i]按大小编号,每次插入到树状数组的对应位置就可以查询出来了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn = 1000000+10;
int a[maxn],cntA[maxn],cntB[maxn],num[maxn];
map<int,int>mp;
int C[maxn];
inline int lowbit(int x)
{
return x&-x;
}
int sum(int x)
{
int ret=0;
while(x>0)
{
ret+=C[x];
x-=lowbit(x);
}
return ret;
}
void add(int x,int v)
{
while(x<maxn)
{
C[x]+=v;
x+=lowbit(x);
}
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n;
scanf("%d",&n);
for(int i = 1;i <= n;++i)
scanf("%d",&a[i]);
for(int i = 1;i <= n;++i)
{
if(mp.find(a[i]) == mp.end())
cntA[i] = mp[a[i]] = 1;
else cntA[i] = ++mp[a[i]];
}
mp.clear();
for(int i = n;i >= 1;--i)
{
if(mp.find(a[i]) == mp.end())
num[i-1] = cntB[i] = mp[a[i]] = 1;
else num[i-1] = cntB[i] = ++mp[a[i]];
}
sort(num,num + n);
int N = unique(num,num+n)- num;
ll ans = 0;
int pos;
pos = pos = lower_bound(num,num+N,cntB[n]) - num;
add(pos+1,1);
for(int i = n-1;i >= 1;--i)
{
pos = lower_bound(num,num+N,cntA[i]) - num;
if(pos > 0) ans +=sum(pos);
pos = lower_bound(num,num+N,cntB[i]) - num;
pos++;
add(pos,1);
}
printf("%I64d\n",ans);
return 0;
}