运用map优化多次查询【Kadomatsu 子序列】

问题

我们有一个长度为 N 的数组 A,要找到三元组 (i, j, k) 满足:

  1. Aᵢ : Aⱼ : Aₖ = 7 : 5 : 3

  2. j 是下标的最小值 或者​ j 是下标的最大值

数学转换

比例关系 Aᵢ : Aⱼ : Aₖ = 7 : 5 : 3 意味着存在一个正数 a,使得:

a 必须是整数,且满足:

  1. Aⱼ = 5a

  2. Aᵢ = 7a

  3. Aₖ = 3a

位置约束分析

条件 min(i, j, k) = j 或 max(i, j, k) = j 意味着:

  1. j 是最大值的情况:i 和 k 都在 j 的左侧(下标小于 j)

  2. j 是最小值的情况:i 和 k 都在 j 的右侧(下标大于 j)

注意:不可能出现 i < j < k 或 k < j < i 的情况,因为那样 j 既不是最小值也不是最大值。

算法设计

对于每个位置 j:

  1. 检查 Aj 是否能被 5 整除

  2. 如果能,计算 a = Aj/5

  3. 计算我们需要的值:

    • val_i = 7a(对应 i 位置的元素值)

    • val_k = 3a(对应 k 位置的元素值)

  4. 统计:

    • j 是最大值的情况:在 j 的左侧统计 val_i 和 val_k 的出现次数

    • j 是最小值的情况:在 j 的右侧统计 val_i 和 val_k 的出现次数

实现细节

我们需要高效地统计左右两侧某个值的出现次数。可以使用map:

  • cnt_left[x]:当前位置左侧值 x 出现的次数

  • cnt_right[x]:当前位置右侧值 x 出现的次数

处理流程:

  1. 初始化 cnt_right包含所有元素

  2. 从左到右遍历每个位置 j:

    • 将 Ajcnt_right中移除(因为它现在在"当前位置",不属于右侧)

    • 处理当前位置 j

    • 将 Aj 加入 cnt_left(为下一个位置准备)

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    复制代码
     int N;
     cin >> N;
     vector<int> A(N);
     for (int i = 0; i < N; i++) {
         cin >> A[i];
     }
     
     // cnt_left: j左侧的值计数,cnt_right: j右侧的值计数
     unordered_map<ll, int> cnt_left, cnt_right;
     
     // 初始化cnt_right包含所有元素
     for (int i = 0; i < N; i++) {
         cnt_right[A[i]]++;
     }
     
     ll ans = 0;
     // 遍历每个位置作为j
     for (int j = 0; j < N; j++) {
         // 将A[j]从右侧计数中移除(现在它位于"当前位置",不属于右侧)
         cnt_right[A[j]]--;
         
         // 检查A[j]是否能被5整除
         if (A[j] % 5 == 0) {
             ll a = A[j] / 5;  // 计算比例因子
             
             // 计算需要的i和k对应的值
             ll val_i = 7 * a;  // A[i] 应该是 7a
             ll val_k = 3 * a;  // A[k] 应该是 3a
             
             // 情况1: j是最大值(i和k在j左侧)
             // cnt_left[val_i] 是左侧val_i的个数
             // cnt_left[val_k] 是左侧val_k的个数
             // 每个val_i和每个val_k可以组成一个三元组
             ans += (ll)cnt_left[val_i] * cnt_left[val_k];
             
             // 情况2: j是最小值(i和k在j右侧)
             ans += (ll)cnt_right[val_i] * cnt_right[val_k];
         }
         
         // 将A[j]加入左侧计数(为下一个j准备)
         cnt_left[A[j]]++;
     }
     
     cout << ans << "\n";
     return 0;

    }

相关推荐
退休倒计时9 分钟前
【每日一题】LeetCode 437. 路径总和 III TypeScript
算法·leetcode·typescript
学逆向的26 分钟前
汇编——内存
开发语言·汇编·算法·网络安全
tachibana231 分钟前
hot100 翻转二叉树(226)
java·数据结构·算法·leetcode
兰令水37 分钟前
leecodecode【面试150】【2026.7.9打卡-java版本】
java·数据结构·leetcode·面试·职场和发展
Piko6141 小时前
锐捷交换机 DHCP Server部署
运维·网络·笔记
生戎马1 小时前
高光谱拼接算法(七)USAC
算法
KuaCpp2 小时前
C++进程(下)
c++
PhotonixBay2 小时前
共聚焦成像核心原理:针孔、PSF与三维形貌测量技术
人工智能·测试工具·算法
取地址符2 小时前
Rust学习笔记(基于Rustlings)(2):数据结构与集合
笔记·学习·rust
来一碗刘肉面2 小时前
C++中的引用语法
c++·算法