题意:给出数组A,定义f(l,r,x)为A[]的下标l到r之间,等于x的元素数。i和j符合f(1,i,a[i])>f(j,n,a[j]),求有多少对这样的(i,j).
解法:分别从左到右,由右到左预处理到某个下标为止有多少个数等于该下标,用map维护。
然后树状数组更新每个f(j,n,a[j]),预处理完毕,接下来,从左往右扫过去,每次从树状数组中删去a[i],因为i != j,i不能用作后面的统计,然后统计getsum(inc[a[i]]-1),
(inc表示从左到右),即查询比此时的a[i]小的f(j,n,a[j])个数。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <map> #define lll __int64 using namespace std; using namespace __gnu_cxx; #define N 1000007 #define M 22int c[N],a[N]; map<int,int> inc,des; int n;int lowbit(int x) {return x & (-x); }void modify(int x,int val) {while(x <= n){c[x] += val;x += lowbit(x);} }int getsum(int x) {int res = 0;while(x > 0){res += c[x];x -= lowbit(x);}return res; }int main() {int i;inc.clear();des.clear();memset(c,0,sizeof(c));scanf("%d",&n);for(i=1;i<=n;i++)scanf("%d",&a[i]);for(i=n;i>=1;i--){des[a[i]]++;modify(des[a[i]],1);}lll ans = 0;for(i=1;i<=n;i++){inc[a[i]]++;modify(des[a[i]],-1);des[a[i]]--;ans += getsum(inc[a[i]]-1);}printf("%I64d\n",ans);return 0; }