题目

给定一个长度为 n 的序列 a1,a2,,an。请你找出一共有多少个数对 (i,j) 满足 ai<i<aj<j ,1i,jn
例如,长度为 5 的序列 [1,1,2,3,8,2,1,4],有 3 个满足要求的数对:(2,4)(2,8)(3,8)

  1. 数对 (2,4)a2=1, a4=3 满足 a2<2<a4<4
  2. 数对 (2,8)a2=1a8=4 满足 a2<2<a8<8;
  3. 数对 (3,8)a3=2a8=4 满足 a3<3<a8<8

限制:

  • 1n2×106
  • 0ai109

算法分析

本题难度中等,考察枚举思想与前缀和技巧。

做法1:

从左到右枚举每个元素 aj,如果 aj<j,则在前 j1 个元素中找有多少个 i 满足 ai<i<aj
时间复杂度:O(n2)
这个做法可以拿到 50

做法2:

遍历序列 a,如果当前元素满足 aj<j,需要在 a1aj1 中找满足 ai<i<aj 的数量进行累加。
可以预处理前 j 个元素中满足 aj<j 的个数,用 Sj 表示,则在 a1aj1 中找满足 ai<i<aj 的数量可以转换成 Saj1,其中 aj11
时间复杂度:O(n)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
cin >> n;
vector<int> a(n+1);
rep(i, n) cin >> a[i];
vector<int> s(n+1);
rep(i, n) s[i] = s[i-1]+(a[i]<i);
ll ans = 0;
rep(j, n) {
if (a[j] < j and a[j]-1 >= 1) {
ans += s[a[j]-1];
}
}
cout << ans << '\n';
return 0;
}