洛谷B4006 [GESP202406 四级] 宝箱

原理

  1. 排序预处理
    将宝箱数值排序,使后续操作可以基于有序数组进行。
  2. 滑动窗口(双指针)
    维护一个满足极差条件的窗口 [i,j],动态调整窗口大小。
  3. 贪心求最大值
    在满足极差约束的前提下,计算窗口内数值之和并记录最大值。

步骤

  1. 输入处理
    读取宝箱数量 n、极差限制 k 和宝箱数值数组 A
  2. 数组排序
    对数组进行升序排序,确保后续操作可以基于有序数组。
  3. 滑动窗口遍历
    • 右指针 j 逐步扩展窗口右边界。
    • 左指针 i 动态调整,确保窗口内极差 A[j]-A[i] <= k
    • 计算当前窗口的和,并更新最大值。
  4. 输出结果
    返回满足条件的最大子数组和。

图示法表示步骤

输入数组: [3, 1, 5, 2] → 排序后: [1, 2, 3, 5]
k=2

初始化 i=0, ans=0, max=0
-------------------------------------
j=0 → A[0]=1
ans=1
窗口极差 1-1=0 ≤2 → max=1

j=1 → A[1]=2
ans=1+2=3
窗口极差 2-1=1 ≤2 → max=3

j=2 → A[2]=3
ans=3+3=6
窗口极差 3-1=2 ≤2 → max=6

j=3 → A[3]=5
ans=6+5=11
窗口极差 5-1=4 >2 → 移动i:
  ans=11-1=10, i=1 → 极差5-2=3 >2
  ans=10-2=8, i=2 → 极差5-3=2 ≤2
更新max=8
最终输出8

代码程序及关键行注释

#include 
#include 
#include 
using namespace std;

int casebag(int n, int k, vector& A) {
    int i = 0;          // 窗口左指针
    int ans = 0;        // 当前窗口的和
    int max_sum = 0;    // 记录最大和

    for (int j = 0; j < n; j++) {  // 右指针j逐步扩展窗口
        ans += A[j];               // 将A[j]加入当前窗口

        // 维护窗口极差约束:A[j]-A[i] <=k
        while (A[j] - A[i] > k) {  // 极差超过k时缩小窗口
            ans -= A[i];           // 从和中移除A[i]
            i++;                   // 左指针右移
        }

        // 更新最大和
        if (max_sum < ans) {
            max_sum = ans;
        }
    }
    return max_sum;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector A(n);
    for (int i = 0; i < n; i++) {
        cin >> A[i];
    }
    sort(A.begin(), A.end());      // 关键排序操作
    int ans = casebag(n, k, A);
    cout << ans << endl;
    return 0;
}

时间复杂度

  1. 排序操作
    sort(A.begin(), A.end()) 的时间复杂度为 O(n log n)
  2. 滑动窗口遍历
    casebag 函数中双指针遍历的时间复杂度为 O(n)
  3. 总时间复杂度
    O(n log n),由排序操作主导。

总结

  1. 核心思想
    通过排序将极差约束转化为滑动窗口问题,利用双指针高效维护窗口。
  2. 关键优化
    排序后窗口极差仅需计算 A[j]-A[i],无需遍历子数组求最大最小值。
  3. 适用场景
    适用于需要满足极差约束且求最大子数组和的场景,时间复杂度可接受。

你可能感兴趣的:(个人算法提高,算法,c++)