递增三元组

给定三个整数数组

\(A=[A_1,A_2,…A_N],\)
\(B=[B_1,B_2,…B_N],\)
\(C=[C_1,C_2,…C_N],\)

请你统计有多少个三元组 (i,j,k) 满足:

\(1 ≤ i,j,k ≤ N\)
\(A_i < B_j < C_k\)
输入格式
第一行包含一个整数 N。

第二行包含 N 个整数 \(A_1,A_2,…A_N。\)

第三行包含 N 个整数 \(B_1,B_2,…B_N。\)

第四行包含 N 个整数 \(C_1,C_2,…C_N。\)

输出格式
一个整数表示答案。

数据范围
\(1 ≤ N ≤ 10^5,\)
\(0 ≤ A_i,B_i,C_i ≤ 10^5\)
输入样例:

3
1 1 1
2 2 2
3 3 3

输出样例:

27

方法1. 排序+二分:

将三个数组从小到大排序,枚举中间的数字也就是B[j], 在数组A中找到第一个大于等于B[j]的下标x, 在数组C中找到第一个大于B[j]的下标y,

这个时候需要求出A数组中小于B[j]的数量,C数组中大于B[j]的数量; 由于我们用二分求出了下标,求数量就很简单了,(这一步的求法取决于数组下标从0开始还是从1开始),我这里使用的是1base,所以数组A中小于B[j]的数量是(i-1) , 数组C中大于B[j]的数量是 (n-j+1), 运用乘法原理相乘累加进答案

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a;i < b;i++)
typedef long long ll;

const int N = 100010;
int a[N], b[N], c[N], n;
int main() {
    scanf("%d", &n);
    rep(i,1,n+1) scanf("%d", &a[i]);
    rep(i,1,n+1) scanf("%d", &b[i]);
    rep(i,1,n+1) scanf("%d", &c[i]);
    sort(a+1,a+1+n);sort(b+1,b+1+n);sort(c+1,c+1+n);
    ll res = 0;
    rep(_,1,n+1) {
        int x = b[_];
        int i = lower_bound(a+1,a+1+n,x) - a;
        int j =  upper_bound(c+1,c+1+n,x) - c;
        res += 1ll*(i-1)*(n-j+1);
        //printf("%d %d\n", i, j);
    }
    printf("%lld\n", res);
    return 0;
}

方法2. 前缀和

用前缀和来求一个数组中小于某个数的个数和大于某个数的个数(这种做法与数值范围有关) 空间换时间

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a;i < b;i++)
typedef long long ll;

const int N = 100010;
int a[N], b[N], c[N], n;
ll sa[N], sc[N];

int main() {
    scanf("%d", &n);
    rep(i,1,n+1) {
        scanf("%d", &a[i]), a[i]++;
        sa[a[i]]++;
    }
    rep(i,1,n+1) scanf("%d", &b[i]), b[i]++;
    rep(i,1,n+1) {
        scanf("%d", &c[i]), c[i]++;
        sc[c[i]]++;
    }
    rep(i,1,N) {
        sa[i] += sa[i-1];
        sc[i] += sc[i-1];
    }

    ll res = 0;
    rep(_,1,n+1) {
        int x = b[_];
        res += 1ll*(sa[x-1]*(n-sc[x]));
    }
    printf("%lld\n", res);
    return 0;
}
posted @ 2023-01-11 18:42  junlin623  阅读(105)  评论(0编辑  收藏  举报