题意: 给出一串数字序列,寻找像
a
i
>
j
,
a
j
>
i
a_i>j,a_j>i
ai>j,aj>i这种数字对的数量。
思路: 根据题意可以列出
∑
i
=
1
n
−
1
∑
j
=
i
+
1
n
[
a
i
≥
j
]
[
a
j
≥
i
]
\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}[a_i \geq j][a_j \geq i]
∑i=1n−1∑j=i+1n[ai≥j][aj≥i]
计算这个式子的数量就好。大于
n
n
n的按
n
n
n算。主席树模板题。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e5 + 10;
int n, q, a[N], root[N], cnt;
vector<int> v;
struct node {
int l, r, num;
} zxs[N * 40];
void add(int l, int r, int pre, int &now, int pos) {
zxs[++cnt] = zxs[pre], now = cnt, zxs[cnt].num++;
if(l == r)
return;
int m = (l + r) >> 1;
if(pos <= m)
add(l, m, zxs[pre].l, zxs[cnt].l, pos);
else
add(m + 1, r, zxs[pre].r, zxs[cnt].r, pos);
}
int query(int k, int l, int r, int L, int R) {//求比k小的数的个数
if(k > r)
return zxs[R].num - zxs[L].num;
int m = (l + r) >> 1, ans = 0;
if(k > l)
ans += query(k, l, m, zxs[L].l, zxs[R].l);
if(k > m + 1)
ans += query(k, m + 1, r, zxs[L].r, zxs[R].r);
return ans;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] = min(n, a[i]);
add(1, n, root[i - 1], root[i], a[i]);
}
ll ans = 0;
for(int i = 1; i <= n - 1; i++)
if(a[i] > i)
ans += (a[i] - i - query(i, 1, n, root[i - 1], root[a[i]]));
printf("%lld", ans);
return 0;
}