二分做法
考虑到(A_i < B_j < C_k),如果以(A_i)为基准进行二分,时间复杂度为:(O(n^2log^2n))。
若以(B_j)为基准,则只需在(A)数组中查找最后一个小于(B_j)的位置,以及(C)数组中查找第一个大于(B_j)的位置,时间复杂度为:(O(nlogn))。
const int N=1e5+10;
int a[N],b[N],c[N];
int n;
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
for(int i=0;i<n;i++) cin>>b[i];
sort(b,b+n);
for(int i=0;i<n;i++) cin>>c[i];
sort(c,c+n);
LL res=0;
for(int i=0;i<n;i++)
{
int ra=lower_bound(a,a+n,b[i])-a;
int lc=upper_bound(c,c+n,b[i])-c;
res+=(LL)ra*(n-lc);
}
cout<<res<<endl;
//system("pause");
return 0;
}
双指针做法
由于存在单调性,可用双指针替代二分。
const int N=1e5+10;
int a[N],b[N],c[N];
int n;
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
for(int i=0;i<n;i++) cin>>b[i];
sort(b,b+n);
for(int i=0;i<n;i++) cin>>c[i];
sort(c,c+n);
LL res=0;
int ra=0,lc=0;
for(int i=0;i<n;i++)
{
while(ra<n && a[ra] < b[i]) ra++;
while(lc<n && c[lc] <= b[i]) lc++;
res+=(LL)ra*(n-lc);
}
cout<<res<<endl;
//system("pause");
return 0;
}
前缀和做法
开两个桶分别记录数组(a)和(c)中各数字出现的次数,对桶数组求前缀和,之后枚举(b)数组中的每个数累加答案。
为方便前缀和处理,将(a)、(b)、(c)读入的数字均做加一处理。
const int N=1e5+10;
int a[N],b[N],c[N];
int cnta[N],cntc[N];
int suma[N],sumc[N];
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
cnta[++a[i]]++;
}
for(int i=1;i<N;i++) suma[i]=suma[i-1]+cnta[i];
for(int i=1;i<=n;i++) cin>>b[i],b[i]++;
for(int i=1;i<=n;i++)
{
cin>>c[i];
cntc[++c[i]]++;
}
for(int i=1;i<N;i++) sumc[i]=sumc[i-1]+cntc[i];
LL res=0;
for(int i=1;i<=n;i++)
res+=(LL)suma[b[i]-1]*(sumc[N-1]-sumc[b[i]]);
cout<<res<<endl;
//system("pause");
return 0;
}