题目入口
题目描述
给定三个整数数组
A=[A1,A2,…AN], B=[B1,B2,…BN], C=[C1,C2,…CN],
请你统计有多少个三元组 (i,j,k) 满足:
1.1≤i,j,k≤N
2.Ai<Bj<Ck
输入格式
第一行包含一个整数 N。
第二行包含 N 个整数 A1,A2,…AN。
第三行包含 N 个整数 B1,B2,…BN。
第四行包含 N 个整数 C1,C2,…CN。
输出格式
一个整数表示答案。
数据范围
1≤N≤1e5
0≤Ai,Bi,Ci≤1e5
输入样例
3
1 1 1
2 2 2
3 3 3
输出样例
27
思路讲解
看过题之后,我们首先联想到的解题方法就是三重循环,将符合要求的进行计数处理,最后输出答案,但是这个做法的时间复杂度是O(n^3),大概就是1e15,超过了时限,所以我们应该对其进行优化,我们可以看一下n的数据范围是1e5,所以这道题的做法时间复杂度应该是O(nlogn)或者是O(n),所以我们只能去枚举A,B,C这三个其中的一个,我们选择枚举B的话,可以对A和C产生一个直接的限制,所以我们选择枚举B,我们枚举每一个B中的元素,求出符合要求的A和C的数量,记为cnta,cntc,然后cnta*cntc即为这一次循环得到符合的三元组的数量,计算出每一次循环的符合要求的三元组的数量,然后将其加和即为答案,我们求符合要求的A和C的数量可以使用排序加二分和前缀和这两种任意一种来求解。
代码
排序加二分
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
int n;
int A[N],B[N],C[N];
//记录符合要求的三元组的数量
long long ans;
/*
算法思路:
枚举B然后看A和C中哪些满足条件即可
本次使用的是排序+二分
*/
int main()
{
cin >> n;
for(int i = 1;i <= n;i++)
{
cin >> A[i];
}
for(int i = 1;i <= n;i++)
{
cin >> B[i];
}
for(int i = 1;i <= n;i++)
{
cin >> C[i];
}
sort(A+1,A+n+1);
sort(C+1,C+n+1);
for(int i = 1;i <= n;i++)
{
int l = 1;
int r = n;
while(l < r)
{
int mid = l + r + 1 >> 1;
if(A[mid] >= B[i])r = mid - 1;
else l = mid;
}
long long tempA;
if(A[l] >= B[i])tempA = 0;
else tempA = l;
l = 1;
r = n;
while(l < r)
{
int mid = l + r >> 1;
if(C[mid] > B[i])r = mid;
else l = mid + 1;
}
long long tempC;
if(C[l] <= B[i])tempC = 0;
else tempC = n - l + 1;
ans += tempA * tempC;
}
cout << ans << endl;
return 0;
}
前缀和
#include<iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
int n;
int A[N],B[N],C[N];
//sa[i]记录A中1到i中每个数出现的次数的总和
//sc[i]记录A中1到i中每个数出现的次数的总和
int sa[N],sc[N];
int main()
{
cin >> n;
//由于A[i],B[i],C[i]都有可能取到0,所以为了避免前缀和的边界问题,将其都加1
for(int i = 1;i <= n;i++)scanf("%d",&A[i]),A[i]++;
for(int i = 1;i <= n;i++)scanf("%d",&B[i]),B[i]++;
for(int i = 1;i <= n;i++)scanf("%d",&C[i]),C[i]++;
for(int i = 1;i <= n;i++)sa[A[i]]++;
//计算前缀和
for(int i = 1;i < N;i++)sa[i] += sa[i-1];
for(int i = 1;i <= n;i++)sc[C[i]]++;
//计算前缀和
for(int i = 1;i < N;i++)sc[i] += sc[i-1];
LL res = 0;
for(int i = 1;i <= n;i++)
{
int cnta = sa[B[i]-1];
int cntc = sc[N-1] - sc[B[i]];
res += (LL)cnta * cntc;
}
cout << res << endl;
return 0;
}