目录
问题描述
A = [A1, A2, … AN],
B = [B1, B2, … BN],
C = [C1, C2, … CN],
请你统计有多少个三元组(i, j, k) 满足:
1 <= i, j, k <= N
Ai < Bj < Ck
输入
第一行包含一个整数N。
第二行包含N个整数A1, A2, … AN。
第三行包含N个整数B1, B2, … BN。
第四行包含N个整数C1, C2, … CN。
1 <= N <= 100000 0 <= Ai, Bi, Ci <= 100000
输出
一个整数表示答案
样例输入
3
1 1 1
2 2 2
3 3 3
样例输出
27
问题分析
对于本题可以采取暴力求解的方式,使用三重嵌套循环,逐个枚举,时间复杂度会达到
O(n^3),N达到100000时会超时严重:
#include<bits/stdc++.h>
using namespace std;
const int N=1000000;
int A[N],B[N],C[N];
int main()
{ int n;
cin>>n;
for(int i=0;i<n;i++) cin>>A[i];
for(int i=0;i<n;i++)cin>>B[i];
for(int i=0;i<n;i++)cin>>C[i];
int count=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
if(A[i]<B[j]&&B[j]<=C[k])
count++;
cout<<count;
return 0;
}
算法优化
对算法进行改进将A[i]和B[j]大小比较和B[j]和C[k]的大小比较分开来比较,进行统计,再将统计的结果相乘即可,counta为A中小于B[i]的个数;countb为B中小于C[i]的个数,对枚举次序进行调整,时间复杂度就会降低为O(n^2):
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
{
if(A[i]<B[j]) counta++;
if(B[i]<C[j]) countb++;
}
num+=counta*countb;
counta=0;
countb=0;
}
仔细分析,统计一个数比一个序列大的数据数目,本质上可以转换成查找算法,最高效的查找算法就是二分法,首先要对这三个数组进行排序。
排序后可进行二分查找,A中小于B[i]中最大的一个A[i],求出数组a中小于B[i]的个数wa,当A[j]<B[i]时,A[0]~A[j]一定小于B[i],以此类推C中第一个比B[i]大的数,求出数组C中小于B[i]的数wc,只要找到第一个比B[i]大的数,那么它之后的数也比B[i]大。wa*wc就是递增三元组的总个数。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[100000],b[100000],c[100000];
//找出数组A中小于B[i]的最大数的下标
int small(int n,int a[],int key)
{ int left=1,right=n;
while(left<right){
int mid=left+right+1/2;
if(a[mid]<key)left=mid;
else right=mid -1;
}
return left;
}
//找出数组C中第一个大于B[i]的数
int big(int n,int c[],int key)
{ int left=1,right=n;
while(left<right){
int mid=(left+right)/2;
if(c[mid]>key) right=mid;
else left=mid +1;
}
return left;
}
int main()
{ int n;
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(b+1,b+n+1);
sort(c+1,c+n+1);//排序
LL count=0;
for(int i=1;i<=n;i++)
{
int key=b[i];
LL wa=small(n,a,key);
LL wc=big(n,c,key);
if(a[wa]<key&&c[wc]>key) count +=(wa-1)*(n+1-wc);
}
cout<<count<<endl;
return 0;
}
运行结果