递增三元组
给定三个整数数组
\(A=[A_1,A_2,…A_N],\)
\(B=[B_1,B_2,…B_N],\)
\(C=[C_1,C_2,…C_N],\)
请你统计有多少个三元组 (i,j,k) 满足:
\(1 ≤ i,j,k ≤ N\)
\(A_i < B_j < C_k\)
输入格式
第一行包含一个整数 N。
第二行包含 N 个整数 \(A_1,A_2,…A_N。\)
第三行包含 N 个整数 \(B_1,B_2,…B_N。\)
第四行包含 N 个整数 \(C_1,C_2,…C_N。\)
输出格式
一个整数表示答案。
数据范围
\(1 ≤ N ≤ 10^5,\)
\(0 ≤ A_i,B_i,C_i ≤ 10^5\)
输入样例:
3
1 1 1
2 2 2
3 3 3
输出样例:
27
方法1. 排序+二分:
将三个数组从小到大排序,枚举中间的数字也就是B[j], 在数组A中找到第一个大于等于B[j]的下标x, 在数组C中找到第一个大于B[j]的下标y,
这个时候需要求出A数组中小于B[j]的数量,C数组中大于B[j]的数量; 由于我们用二分求出了下标,求数量就很简单了,(这一步的求法取决于数组下标从0开始还是从1开始),我这里使用的是1base,所以数组A中小于B[j]的数量是(i-1) , 数组C中大于B[j]的数量是 (n-j+1), 运用乘法原理相乘累加进答案
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a;i < b;i++)
typedef long long ll;
const int N = 100010;
int a[N], b[N], c[N], n;
int main() {
scanf("%d", &n);
rep(i,1,n+1) scanf("%d", &a[i]);
rep(i,1,n+1) scanf("%d", &b[i]);
rep(i,1,n+1) scanf("%d", &c[i]);
sort(a+1,a+1+n);sort(b+1,b+1+n);sort(c+1,c+1+n);
ll res = 0;
rep(_,1,n+1) {
int x = b[_];
int i = lower_bound(a+1,a+1+n,x) - a;
int j = upper_bound(c+1,c+1+n,x) - c;
res += 1ll*(i-1)*(n-j+1);
//printf("%d %d\n", i, j);
}
printf("%lld\n", res);
return 0;
}
方法2. 前缀和
用前缀和来求一个数组中小于某个数的个数和大于某个数的个数(这种做法与数值范围有关) 空间换时间
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a;i < b;i++)
typedef long long ll;
const int N = 100010;
int a[N], b[N], c[N], n;
ll sa[N], sc[N];
int main() {
scanf("%d", &n);
rep(i,1,n+1) {
scanf("%d", &a[i]), a[i]++;
sa[a[i]]++;
}
rep(i,1,n+1) scanf("%d", &b[i]), b[i]++;
rep(i,1,n+1) {
scanf("%d", &c[i]), c[i]++;
sc[c[i]]++;
}
rep(i,1,N) {
sa[i] += sa[i-1];
sc[i] += sc[i-1];
}
ll res = 0;
rep(_,1,n+1) {
int x = b[_];
res += 1ll*(sa[x-1]*(n-sc[x]));
}
printf("%lld\n", res);
return 0;
}
你只管出发,旅途自有风景~~