当前位置: 首页 > news >正文

题解:P8667 [蓝桥杯 2018 省 B] 递增三元组 (暴力+二分)

题解:P8667 [蓝桥杯 2018 省 B] 递增三元组

题目传送门

题目链接

一、题目描述

给定三个整数数组 A、B、C,每个数组包含 N 个元素。要求统计满足 A[i] < B[j] < C[k] 的三元组 (i, j, k) 的数量。

二、题目分析

我们需要找到所有满足 A[i] < B[j] < C[k] 的三元组。直接暴力枚举三个数组的所有组合时间复杂度为 O(N³),对于 N=1e5 的数据显然不可行。

三、解题思路

  1. 排序优化:先对数组 A 和 C 进行排序,这样可以利用二分查找快速统计满足条件的元素数量。
  2. 二分查找:对于每个 B[j],在 A 中找到比它小的元素数量,在 C 中找到比它大的元素数量,然后将这两个数量相乘得到以该 B[j] 为中间值的所有有效三元组数量。
  3. 累计求和:将所有 B[j] 对应的有效三元组数量累加,得到最终答案。

四、算法讲解

  1. 排序:首先对数组 A 和 C 进行升序排序,以便后续的二分查找操作。
  2. 二分查找
    • 对于每个 B[j],在 A 中使用二分查找找到最后一个小于 B[j] 的元素位置,该位置左边的元素都满足 A[i] < B[j]。
    • 在 C 中使用二分查找找到第一个大于 B[j] 的元素位置,该位置右边的元素都满足 C[k] > B[j]。
  3. 组合计算:将每个 B[j] 对应的满足条件的 A 元素数量和 C 元素数量相乘,得到以该 B[j] 为中间值的所有有效三元组数量。

五、代码实现

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 10;
int n;
int a[N], b[N], c[N];

// 暴力解法,时间复杂度 O(N³),只能通过小数据
void solve1()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        cin >> b[i];
    for (int i = 1; i <= n; i++)
        cin >> c[i];
    int cnt = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            for (int k = 1; k <= n; k++)
            {
                if (a[i] < b[j] && b[j] < c[k])
                    cnt++;
            }
    cout << cnt << "\n";
}

// 自定义二分查找实现
int bifind_a(int x)
{
    int l = -1, r = n + 1;
    while ( l + 1 != r)
    {
        int mid = l + r >> 1;
        if (a[mid] < x)
            l = mid;
        else
            r = mid;
    }
    if (a[l] < x) return l; // 返回小于x的元素个数
    else return 0;
}

int bifind_c(int x)
{
    int l = -1, r = n + 1;
    while (l + 1 != r)
    {
        int mid = l + r >> 1;
        if (c[mid] <= x)
            l = mid;
        else
            r = mid;
    }
    if (c[r] > x)
        return n - r + 1; // 返回大于x的元素个数
    else
        return 0;
}

// 使用自定义二分查找的优化解法
void solve2()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        cin >> b[i];
    for (int i = 1; i <= n; i++)
        cin >> c[i];
    int cnt = 0;
    sort(a + 1, a + 1 + n);  // 对A数组排序
    sort(c + 1, c + 1 + n);  // 对C数组排序
    for (int i = 1; i <= n; i++)
    {   
        int x = bifind_a(b[i]);  // A中比b[i]小的元素个数
        int y = bifind_c(b[i]);  // C中比b[i]大的元素个数
        cnt += x * y;            // 累加组合数
    }
    cout << cnt << "\n";
}

// 使用STL二分查找函数的优化解法
void solve3()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= n; i++)
        cin >> b[i];
    for (int i = 1; i <= n; i++)
        cin >> c[i];
    int cnt = 0;
    sort(a + 1, a + 1 + n);  // 对A数组排序
    sort(c + 1, c + 1 + n);  // 对C数组排序
    for (int i = 1; i <= n; i++)
    {
        // 使用lower_bound找到第一个不小于b[i]的位置
        int x = lower_bound(a + 1, a + 1 + n, b[i]) - a - 1;
        // 使用upper_bound找到第一个大于b[i]的位置
        int y = n - (upper_bound(c + 1, c + 1 + n, b[i]) - c) + 1;
        cnt += x * y;
    }
    cout << cnt << "\n";
}

signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    solve2();  // 推荐使用solve2或solve3
    return 0;
}

六、重点细节

  1. 数组排序:必须对 A 和 C 数组进行排序才能使用二分查找。
  2. 边界处理:在自定义二分查找时,要注意处理所有元素都满足或不满足条件的情况。
  3. 索引处理:使用 STL 的 lower_bound 和 upper_bound 时,要注意返回的是迭代器,需要减去数组首地址转换为索引。
  4. 数据类型:使用 long long 防止中间结果溢出。

七、复杂度分析

  1. 时间复杂度
    • 排序:O(N log N)
    • 二分查找:对于每个 B[j] 进行两次二分查找,O(log N),总共 O(N log N)
    • 总时间复杂度:O(N log N)
  2. 空间复杂度:O(N),仅需要存储三个数组。

八、总结

本题通过排序和二分查找将时间复杂度从 O(N³) 优化到 O(N log N),是典型的利用排序和二分查找优化统计问题的例子。关键在于将三重循环分解为三个独立的一重循环,通过预处理(排序)和快速查询(二分)来大幅提升效率。

相关文章:

  • DeepSeek原生稀疏注意力(Native Sparse Attention, NSA)算法介绍
  • 【SpringCloud】LoadBalance-负载均衡
  • html处理Base文件流
  • 【C++项目】从零实现RPC框架「三」:项⽬抽象层实现
  • 动手实现docker全过程
  • python求解非线性方程组
  • 蓝桥杯——统计子矩阵
  • 设计模式学习(1)
  • 顺据结构(C\C++)——双向链表
  • 【Qt】游戏场景和图元
  • rbpf虚拟机-JIT和解释执行对比
  • 数据处理的两种范式:深入解析OLTP与OLAP系统
  • 自动驾驶实验
  • 13届省赛python A组:10.数的拆分
  • 【Linux】进程间通信(IPC)-- 无名管道、命名管道
  • 请求Header(Request Headers)详解
  • LeetCode算法题(Go语言实现)_22
  • 操作系统的运行机制
  • 运放的噪声计算
  • 同步SVPWM调制策略的初步学习记录
  • 免费视频网站推广软件/站长源码
  • 知名网站域名被抢注/提高网站收录的方法
  • 网站推广如何做的/公司网页制作需要多少钱
  • 郑州做商城网站公司/宁波seo关键词优化制作
  • 网站加入搜索引擎怎么做/seo怎么刷排名
  • 中国城乡住房建设部网站/下载百度app