第九届蓝桥杯C++B组:递增三元组

给定三个整数数组

A = [A1, A2, ... AN],

B = [B1, B2, ... BN],

C = [C1, C2, ... CN],

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

1. 1 <= i, j, k <= N  

2. Ai < Bj < Ck  

【输入格式】

第一行包含一个整数N。

第二行包含N个整数A1, A2, ... AN。

第三行包含N个整数B1, B2, ... BN。

第四行包含N个整数C1, C2, ... CN。

对于30%的数据,1 <= N <= 100  

对于60%的数据,1 <= N <= 1000

对于100%的数据,1 <= N <= 100000 0 <= Ai, Bi, Ci <= 100000

【输出格式】

一个整数表示答案

【样例输入】

3

1 1 1

2 2 2

3 3 3

【样例输出】

27

资源约定:

峰值内存消耗(含虚拟机) < 256M

CPU消耗  < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

注意:

main函数需要返回0;

只使用ANSI C/ANSI C++ 标准;

不要调用依赖于编译环境或操作系统的特殊函数。

所有依赖的函数必须明确地在源文件中 #include <xxx>

不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。

思路(难点:优化——二分):

一开始想到的是暴力求解,排序后,三个for循环寻找依次遍历三个数组中寻找在B比A大的条件下 C比B大个数,依次累加,但是这样会造成超时(如果数据都是100000),因此需要优化。

优化后:

固定一个B数组,然后在A数组中寻找比B[i]小的个数x,在C数组中寻找B[i]大的个数y,最后结果等于把x*y【也就是两边的个数组合起来】。两个个数的寻找的方法使用算法库里的二分查找寻找法,这样就只用一个for循环加上两个二分查找法(时间复杂度:logn)的情况下,不会造成超时。

参考代码:


#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 100010;
int A[maxn], B[maxn], C[maxn];

int main(){
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &A[i]);
    }
    sort(A + 1, A + n + 1);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &B[i]);
    }
    sort(B + 1, B + n + 1);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &C[i]);
    }
    sort(C + 1, C + n + 1);

    int sum = 0;
    for (int j = 1; j <= n; ++j) {
        //两个调用算法库里的函数,返回的都是数组的位置(即指针),为了获得下标 需要减去数组首地址
        //寻找第一个大于等于b[j]的A数组的下标,然后小于b[i]个数等于下标减1
        int x = (lower_bound(A + 1, A + n + 1, B[j]) - A) - 1;
        //寻找第一个大于b[j]的C数组的下标,然后小于等于b[i]个数等于下标减1,大于b[i]的个数等于n减小于b[i]的数
        int y = n - (upper_bound(C + 1, C + n + 1, B[j]) - C) + 1;
        sum += x * y;
    }
    printf("%d", sum);
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值