题目链接
tag
二维偏序,树状数组
solution
题目可以简化为计算有多少(pair(i,j)) 满足 (1 leq i leq n) (and) (1 leq j leq n) (and) (i < j) (and) (f(1, i, a[i]) > f(j, n, a[j]))
记(pre[i]) 表示(f(1, i, a[i])),(suf[i])表示(f(i, n, a[i])),由于(a[i] leq 10^9)可以利用map或者离散化前后两次遍历(O(n))求出(pre, suf)
因为是计算对于每个(pre[i]),有多少(j > i) (and) (suf[j] < pre[i]),经典的二位偏序问题,我们维护一个表示suf[j]值出现次数的树状数组,倒着枚举(i),求出有多少(suf[j] ∈ [1, pre[i] - 1]),即(query(pre[i-1])), 然后树状数组中下标(suf[j])的值加一,即(add(suf[j], 1)),表示这个值出现的次数增加一次
需要每次统计前缀和并且单点更新,正好是树状数组可以解决的
code
//created by pyoxiao on 2021/01/18
#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define CL(a, b) memset(a, b, sizeof(a))
using namespace std;
const int mod = 1e9 + 7;
LL fpow(LL a, LL b, LL p = mod){LL ans = 1; a %= p; while(b) {if(b & 1) ans = ans * a % p; b >>= 1; a = a * a % p;} return ans;}
LL gcd(LL a, LL b){return b == 0 ? a : gcd(b, a % b);}
const int N = 1e6 + 7;
int n, a[N];
vector<int> ls;
struct tr{
int c[N];
int lowbit(int x){ return x & -x; }
void add(int x, int y) {
while(x < N) {
c[x] += y;
x += lowbit(x);
}
}
int ask(int x) {
int ans = 0;
while(x) {
ans += c[x];
x -= lowbit(x);
}
return ans;
}
}tt;
int cnt[N], cnt2[N], pre[N], suf[N];
void solve() {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%d", a + i);
ls.pb(a[i]);
}
sort(ls.begin(), ls.end());
ls.erase(unique(ls.begin(), ls.end()), ls.end());
for(int i = 1; i <= n; i ++) {
a[i] = lower_bound(ls.begin(), ls.end(), a[i]) - ls.begin() + 1;
}
for(int i = 1; i <= n; i ++) {
pre[i] = ++ cnt[a[i]];
}
for(int i = n; i >= 1; i --) {
suf[i] = ++cnt2[a[i]];
}
LL ans = 0;
for(int i = n; i >= 1; i --) {
ans += tt.ask(pre[i] - 1);
tt.add(suf[i], 1);
}
printf("%lld
", ans);
}
int main() {
int T = 1;
// scanf("%d", &T);
while(T --)
solve();
return 0;
}