输入样例:
3
1 1 1
2 2 2
3 3 3
输出样例:
27
解题思路:
因为数据规模为10^5,所以只能用一重循环,而通过最中间一行的遍历恰好能同时满足对前一行和后一行的遍历。设第一到第三行分别为:a[i],b[j],c[k],只需要找出在a数组中比b[j]小的元素个数,在c数组中比b[j]大的元素个数。
1. 前缀和:先将a数组中的元素映射到map中,map通过cnt数组来模拟,cnt[i] = j :就表示元素i的个数是j,再求前缀和数组s[i],也可以直接覆盖到cnt数组上,所以s[i] = j :就表示成了从0到i的元素个数是j个,当找小于数组中的某个数b[i]的个数时,直接查找前缀和数组cnt[b[i]-1]的值便可以直接求出。
因为前缀和数组计算时需要用到上个值的下标,所以将将三个数组中的每个元素值都加一可以避免数组越界。
2. 双指针: 需要对三个数组先排好序,通过移动上下两个指针从而求出符合条件的元素值的个数。也需要防止指针移动时发生越界。
Java代码:(前缀和)O(n)
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int N = 100000;
int []a = new int[n + 1];
int []b = new int[n + 1];
int []c = new int[n + 1];
String[] split = br.readLine().split(" ");
for(int i = 1; i <= n; i++)
a[i] = Integer.parseInt(split[i - 1]) + 1;
split = br.readLine().split(" ");
for(int i = 1; i <= n; i++)
b[i] = Integer.parseInt(split[i - 1]) + 1;
split = br.readLine().split(" ");
for(int i = 1; i <= n; i++)
c[i] = Integer.parseInt(split[i - 1]) + 1;
int []cnta = new int[N + 1];//cnta[i] = j : 表示i出现了j次
int []cntc = new int[N + 1];
for(int i = 1; i <= n; i++) {
cnta[a[i]]++;//相当于将a[i]哈希
cntc[c[i]]++;
}
for(int i = 1; i <= N; i++) {//此时的cnt[i] = j 表示前缀和含义:不小于i的数共有j个
cnta[i] += cnta[i - 1];
cntc[i] += cntc[i - 1];
}
long ans = 0;//最多有n^3个: 10^15
for(int i = 1; i <= n; i++) {
ans += (long)cnta[b[i] - 1] * (n - cntc[b[i]]);//需要强转!!
}
System.out.println(ans);
}
}
Java代码:(双指针)O(n)
import java.io.*;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int []a = new int[n + 1];
int []b = new int[n + 1];
int []c = new int[n + 1];
String[] split = br.readLine().split(" ");
for(int i = 1; i <= n; i++)
a[i] = Integer.parseInt(split[i - 1]) + 1;
split = br.readLine().split(" ");
for(int i = 1; i <= n; i++)
b[i] = Integer.parseInt(split[i - 1]) + 1;
split = br.readLine().split(" ");
for(int i = 1; i <= n; i++)
c[i] = Integer.parseInt(split[i - 1]) + 1;
Arrays.sort(a);
Arrays.sort(b);
Arrays.sort(c);
int i = 1, k = 1;
long ans = 0;
for(int j = 1; j <= n; j++) {
while(i <= n &&b[j] > a[i]) i++;//要防止下标越界
while(k <= n && c[k] <= b[j]) k++;
ans += (long) (i - 1) * (n - k + 1);//将最开始的1减掉
}
System.out.println(ans);
}
}