这道题可以用两种方法解,分别是快排+二分+前缀和,以及快排+双指针+前缀和,前者的思维难度较简单,但代码长,后者思维难度大,但代码短,那么我先来介绍快排+二分+前缀和;
思路如下:
1:可以发现数组的位置信息对答案没有影响,所以我们可以用讲数组排序,故sort3个数组
2:另外我们可以用额外的数组rcod[j]记录B[j]大于A数组中的多少个数字,这个可以用二分找到对应的下标;
3:将rcod进行前缀和处理;
4:对C、B数组进行与第二部相同的处理,并用变量ans存储答案,每次找到满足C[j]>B[i]的下标i,然后ans+=rcod[i];
下面是具体代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
long long a[N], b[N], c[N];
long long n, ans;
long long rcod[N];
int two(int x) {
int l = 0, r = n;
while (l < r) {
int mid = l + r + 1 >> 1;
if (a[mid] < x) l = mid;
else r = mid - 1;
}
return l;
}
void get() {
for (int i = 1; i <= n; i++)
{
int p;
p = two(b[i]);//二分找下标
rcod[i] = p;
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++) scanf("%lld", &b[i]);
for (int i = 1; i <= n; i++) scanf("%lld", &c[i]);
sort(a + 1, a + 1 + n); sort(b + 1, b + 1 + n); sort(c + 1, c + 1 + n);//进行排序
get();//创建rcod数组
for (int i = 1; i <= n; i++)//将数组进行前缀和处理
rcod[i] += rcod[i - 1];
for (int i = 1; i <= n; i++) {
int l = 0, r = n;
while (l < r) {//二分找下标
int mid = l + r + 1 >> 1;
if (b[mid] < c[i]) l = mid;
else r = mid - 1;
}
ans += rcod[r];//累加结果
}
cout << ans;
}
然后是快排+双指针+前缀和;
思路如下:
1:排序;
2:利用单调性,使用双指针创建rcod数组;
3:同样利用单调性找到满足C[j]>B[i]的下标i,然后ans+=rcod[i];
代码如下;
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
long long a[N], b[N], c[N];
long long n, ans;
long long rcod[N];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++) scanf("%lld", &b[i]);
for (int i = 1; i <= n; i++) scanf("%lld", &c[i]);
sort(a + 1, a + 1 + n); sort(b + 1, b + 1 + n); sort(c + 1, c + 1 + n);
for (int i = 1, j = 1; j <= n; j++) {//双指针创建rcod数组
while (a[i] < b[j] && i <= n) i++;
rcod[j] = i - 1;
}
for (int i = 1; i <= n; i++) rcod[i] += rcod[i - 1];//前缀和处理
for (int i = 1, j = 1; j <= n; j++)//双指针找到对应下标
{
while (b[i] < c[j] && i <= n) i++;
ans += rcod[i - 1];
}
cout << ans;
}
在这里我再说一下我对双指针的理解吧;
这里双指针的所以条件为”单调性“,即某一种状态可以通过另外一种状态进行一次运算得到,有点像线性dp......