题目链接:点击打开链接
题意:给一序列数,定义f(l,r,x)为 l 到 r区间内等于x的数的个数。求对于所有的i,j(1<=i<j<=N),有多少对 f(1, i, ai) > f(j, n, aj)。
实际是一道树状数组的水题,先预处理出 f(1, i, ai) 和 f(j, n, aj),由于数据范围是10^9数组开不下,所以用到map。a数组保存的是f(1, i, ai) ,b数组保存 f(j, n, aj)。
然后树状数组c[i]维护有多少个f(j, n, aj)小于等于i,因为最多有10^6个数,所以只需开这么大的空间,求解的思路和求逆序数一样,从后往前查,每次先查询有多少数小于a[i] (sum(a[i]-1)),然后把b[i]更新进去,边查询边更新。
数据看成了10^5 wa了n次
代码:
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#define ll long long
using namespace std;
int N;
int c[1000010];
int a[1000010];
int b[1000010];
map <ll,int >Hash;
ll d[1000010];
ll lowbit(ll n){
return n&(-n);
}
void input(){
for(ll i=1;i<=N;i++){
scanf("%I64d",&d[i]);
a[i]=0;
c[i]=0;
}
Hash.clear();
}
void update(int p,int x){
while(p<=N){
c[p]+=x;
p+=lowbit(p);
}
}
long long sum(int p){
long long res=0;
while(p>0){
res+=c[p];
p-=lowbit(p);
}
return res;
}
void init(){
for(int i=1;i<=N;i++){
Hash[d[i]]++;
a[i]=Hash[d[i]];
}
Hash.clear();
for(int i=N;i>=1;i--){
Hash[d[i]]++;
b[i]=Hash[d[i]];
}
}
int main(){
while(cin>>N){
input();
init();
long long res=0;
for(int i=N;i>=1;i--){
res+=sum(a[i]-1);
update(b[i],1);
}
cout<<res<<endl;
}
return 0;
}