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

蓝桥杯-小明的彩灯(差分)

问题描述:

在这里插入图片描述

差分数组

1. 什么是差分数组?

差分数组 c 是原数组 a 的“差值表示”,其定义如下:

  • c[0] = a[0]
  • c[i] = a[i] - a[i-1]i ≥ 1

差分数组记录了相邻元素的差值。例如,原数组 a = [1, 3, 5, 2] 对应的差分数组为 c = [1, 2, 2, -3]

2. 差分数组的优势

通过差分数组,可以将区间操作转换为两次单点操作:

  • 若要将区间 [l, r] 的所有元素增加 k,只需执行:
    • c[l] += k
    • c[r+1] -= k
      这一操作的时间复杂度为 O(1),彻底避免了遍历区间。

3. 还原原数组

对差分数组进行前缀和运算即可还原原数组:

  • a[i] = c[0] + c[1] + ... + c[i]
    前缀和的本质是逐步累加差分值,恢复出原数组的实际数值。

解题思路详解

步骤1:构建差分数组

  1. 初始化差分数组 c,长度为 n+1(多一位用于处理右边界)。
  2. 根据原数组 a 的相邻差值填充 c,确保 c[i] = a[i] - a[i-1]

步骤2:处理区间操作

对于每个操作 [l, r, k]

  • c[l] += k,表示从 l 开始的所有元素增加 k
  • c[r+1] -= k,表示在 r+1 处抵消多余的 k,保证操作仅作用于 [l, r]

步骤3:还原修改后的数组

通过前缀和还原最终的数组:

  • c[1] 开始,依次累加 c[i] += c[i-1],最终 c[0...n-1] 即为修改后的原数组。

代码:



    public static void main(String[] args) {
        //通过原数组计算 差分 数组
        //再通过计算出的 差分 数组做 数据操作,例如(要将[l,r]区间所有数组+1)就将c[l]+1 c[r+1]-1
        //对差分数组,做前缀和操作得到原数组
        //有一个坑,虽然数据都是在int范围内,但是会涉及到相加操作,可能会超出int范围,所以我们的差分数组应该设置为long
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] a = new int[n];
        //在创建差分数组的时候长度要设置为a.length + 1这是很有必要的,防止数组越界 这个边界操作(c[r + 1] -= 1;)
        long[] c = new long[n + 1];
        a[0] = sc.nextInt();
        //初始化差分数组
        c[0] = a[0];
        for (int i = 1; i < n; i++) {
            a[i] = sc.nextInt();
            c[i] = a[i] - a[i - 1];
        }
//        System.out.println("原数组a:" + Arrays.toString(a));
//        System.out.println("差分数组c:" + Arrays.toString(c));
        //要将[l,r]区间所有数组+c
        for (int i = 0; i < m; i++) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            int sum = sc.nextInt();

            c[l - 1] += sum;
            c[r] -= sum;
        }
        for (int i = 1; i < n; i++) {
            //这里复原的原理其实很简单
            // 例如对 1 2 3 4 5的[2,4]区间做+1操作,
            // 由于差分数组记录的是第i个数比第i-1个数大多少,之前i比i-1大1,+1操作之后,就是i比i-1大2了,
            // 但是由于我们要求在到[l,r]区间,所以r之后的差分就得还原 所以再做一个-1操作还原
            // 所以还原的时候,就能得到题目要求的数组了
            c[i] += c[i - 1];
        }

        for (int i = 0; i < n; i++) {
            if (c[i] < 0) {
                System.out.print(0 + " ");
            } else
                System.out.print(c[i] + " ");

        }
    }


相关文章:

  • 【网络安全 | 漏洞挖掘】通过分析JS文件实现接口未授权访问与账户接管
  • MicroPython 开发ESP32应用教程 之 Timer、GPIO中断
  • OpenCV图像平滑处理方法详解
  • X 进制减法
  • C++-ffmpeg-2-3-工厂模式封装SDL-9-7
  • Qt上hook钩子的使用,监测键盘和鼠标。
  • Crow介绍及使用
  • 一文了解亿级数据检索:RedisSearch
  • OpenBMC:BmcWeb 处理http请求5 检查权限
  • C#核心学习(十二)面向对象--多态(1)virtual override和base三剑客
  • CExercise_07_1指针和数组_5检查一个整数数组是否是回文,即正序与倒序相同
  • 【C#知识点详解】LinkedList<T>储存结构详解
  • Spring Boot接口返回Long类型的数据时丢失精度的全局处理
  • LCR 131. 砍竹子 I
  • 什么是混合搜索Hybrid Search?
  • Python 小练习系列 | Vol.14:掌握偏函数 partial,用函数更丝滑!
  • 和DeepSeek聊高速公路定向广播
  • NO.79十六届蓝桥杯备战|数据结构-扩展域并查集-带权并查集|团伙|食物链|银河英雄传说(C++)
  • CesiumEarth v1.12 更新,支持安卓平板离线浏览3DTiles格式的三维倾斜模型
  • 【计网】作业4
  • 歪歪小站 wordpress/最好最全的搜索引擎
  • 知乐商城是什么网站/外链推广是什么意思
  • wordpress博客案例/网站seo具体怎么做
  • 工商银行门户网站是什么意思/外贸自建站的推广方式
  • wordpress https 2018/百度seo可能消失
  • 做网站有哪个软件好/百度seo软件