[蓝桥杯][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;
}
posted @ 2021-03-24 10:45  Dazzling!  阅读(49)  评论(0编辑  收藏  举报