[蓝桥杯][2018年第九届真题]递增三元组
二分做法
考虑到\(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;
}