差分专题练习 ——基于罗勇军老师的《蓝桥杯算法入门C/C++》

一、1.重新排序 - 蓝桥云课

算法代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 3;int a[N], d[N], cnt[N];int main() {int n; scanf("%d", &n);for (int i = 1; i <= n; i++) scanf("%d", &a[i]);int m; scanf("%d", &m);long long ans1 = 0, ans2 = 0;// 处理区间查询,更新差分数组 d[]while (m--) {int L, R; scanf("%d%d", &L, &R);d[L]++; d[R+1]--;}// 通过差分数组 d[] 还原累加次数 cnt[]cnt[0] = d[0];for (int i = 1; i <= n; i++) cnt[i] = cnt[i-1] + d[i];// 计算未排序时的累加结果 ans1for (int i = 1; i <= n; i++) ans1 += (long long)a[i] * cnt[i];// 排序 a[] 和 cnt[],计算排序后的累加结果 ans2sort(a + 1, a + 1 + n);sort(cnt + 1, cnt + 1 + n);for (int i = 1; i <= n; i++) ans2 += (long long)a[i] * cnt[i];// 输出结果printf("%lld\n", ans2 - ans1);return 0;
}

代码思路解析

1. 问题背景

        这段代码的目标是高效处理多个区间查询,并对数组 a[] 进行累加操作。通过差分数组 d[] 优化区间修改,避免直接遍历区间内的每个元素。

2. 核心思路

  • 差分数组:记录区间修改的起点和终点,避免逐个修改。

  • 前缀和:通过差分数组还原每个位置的累加次数 cnt[]

  • 排序与匹配:通过排序 a[] 和 cnt[],计算最小和最大累加结果。

3. 代码实现步骤

  1. 输入数组 a[] 和查询次数 m

    • 读取数组 a[] 和查询次数 m,初始化差分数组 d[] 和累加次数数组 cnt[]

  2. 处理区间查询

    • 对每个查询 [L, R],更新差分数组 d[]

      • d[L]++:区间起点加1。

      • d[R+1]--:区间终点外减1(抵消后续影响)。

  3. 还原累加次数 cnt[]

    • 通过差分数组 d[] 计算每个位置的累加次数 cnt[]

      • cnt[i] = cnt[i-1] + d[i]

  4. 计算累加结果

    • 未排序时:直接计算 ans1 = sum(a[i] * cnt[i])

    • 排序后:将 a[] 和 cnt[] 排序,计算 ans2 = sum(a[i] * cnt[i])

  5. 输出结果

    • 输出排序前后的差值 ans2 - ans1

4. 复杂度分析

  • 差分数组更新:每个查询 O(1),总复杂度 O(m)。

  • 累加次数还原:遍历数组 O(n)。

  • 排序:O(nlog⁡n)。

  • 总复杂度:O(m+nlog⁡n),适用于大规模数据处理。

5. 关键点

  • 差分数组:高效记录区间修改。

  • 前缀和:快速还原累加次数。

  • 排序优化:通过排序匹配最小和最大累加结果。

通过上述思路和代码,可以高效解决区间累加问题。

关于 sort 的排序规则和对应问题

1. sort 的默认行为

  • 默认排序规则:C++ 中的 sort 函数默认是按升序排序的。

  • 排序依据sort 会根据元素的值进行排序,而不是它们的原始位置。

2. 排序后的对应问题

在代码中,a[] 和 cnt[] 分别被排序:

sort(a + 1, a + 1 + n);      // 对 a[] 排序
sort(cnt + 1, cnt + 1 + n);  // 对 cnt[] 排序
  • 排序后的结果

    • a[] 和 cnt[] 分别按升序排列。

    • 排序后,a[i] 和 cnt[i] 的对应关系被打破,因为它们各自独立排序。

3. 为什么排序后仍然有效?

  • 目标:代码的目标是计算两种累加结果的差值:

    • 未排序时ans1 = sum(a[i] * cnt[i]),即原始对应关系下的累加结果。

    • 排序后ans2 = sum(a[i] * cnt[i]),即排序后的累加结果。

  • 数学原理

    • 排序后,a[] 和 cnt[] 分别按升序排列,此时 ans2 是 a[] 和 cnt[] 的最小匹配累加结果

    • 由于 a[] 和 cnt[] 都是升序排列,ans2 是 a[] 和 cnt[] 的最小可能累加和

    • 差值 ans2 - ans1 反映了排序对累加结果的影响。

4. 排序的意义

  • 未排序时ans1 是基于原始对应关系的累加结果。

  • 排序后ans2 是基于最小匹配的累加结果。

  • 差值 ans2 - ans1

    • 如果 ans2 < ans1,说明排序后的累加结果更小。

    • 如果 ans2 > ans1,说明排序后的累加结果更大。

    • 差值反映了排序对累加结果的影响。

5. 代码的逻辑

  • 未排序时:直接计算原始对应关系下的累加结果 ans1

  • 排序后:计算最小匹配的累加结果 ans2

  • 输出差值ans2 - ans1,反映排序对累加结果的影响。

6. 示例说明

假设:

  • a[] = [3, 1, 2]

  • cnt[] = [2, 3, 1]

未排序时

  • ans1 = 3*2 + 1*3 + 2*1 = 6 + 3 + 2 = 11

排序后

  • a[] = [1, 2, 3]

  • cnt[] = [1, 2, 3]

  • ans2 = 1*1 + 2*2 + 3*3 = 1 + 4 + 9 = 14

差值

  • ans2 - ans1 = 14 - 11 = 3

二、 P1819 - [NewOJ Week 6] 推箱子 - New Online Judge

 算法代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; // 定义 long long 类型别名为 ll,方便使用
const int N = 1e6 + 10; // 定义常量 N 为 1000010,表示数组的最大大小ll d[N], a[N], sum[N]; // 定义差分数组 d[],原数组 a[],前缀和数组 sum[]int main() {int n, h; scanf("%d%d", &n, &h); // 读取障碍物的尺寸 n 和箱子的高度 h// 处理每一列的空白区域for (int i = 1; i <= n; i++) {int li, hi;scanf("%d%d", &li, &hi); // 读取第 i 列空白区域的起始位置 li 和结束位置 hi// 更新差分数组 d[]d[li]++;      // 从第 li 行开始,空白区域的数量增加 1d[hi + 1]--;  // 从第 hi+1 行开始,空白区域的影响结束}// 用差分数组 d[] 计算原数组 a[]for (int i = 1; i <= n; i++) {a[i] = a[i - 1] + d[i - 1]; // 计算第 i 行的空白数量}// 用原数组 a[] 计算前缀和数组 sum[]for (int i = 1; i <= n; i++) {sum[i] = sum[i - 1] + a[i]; // 计算前 i 行的空白数量总和}// 找到连续 h 行的最大空白数量总和ll ans = sum[h - 1]; // 初始化 ans 为前 h 行的空白数量总和for (int left = 1; left + h - 1 <= n; left++) {// 计算从 left 行开始的连续 h 行的空白数量总和ans = max(ans, sum[left + h - 1] - sum[left - 1]);}// 输出需要清理的障碍物面积cout << (ll)n * h - ans << endl; // 总障碍物面积减去最大空白面积return 0;
}

代码思路

1. 问题分析

  • 问题描述:在一个高度为 H 的箱子的前方有一个长和高均为 N 的障碍物。每一列有一个连续的空白区域,范围是 [l_i, h_i]。需要找到一条高度为 H 的通道,使得箱子可以直接推出去。输出最少需要清理的障碍物面积。

  • 核心目标:找到连续 H 行的空白区域总和最大的区间,然后用总障碍物面积减去这个最大空白面积,得到需要清理的最小障碍物面积。

2. 解决思路

  • 空白区域的表示:每一列的空白区域 [l_i, h_i] 会影响多行的空白数量。

  • 差分数组优化:使用差分数组 d[] 来高效记录每一列空白区域对行的贡献。

  • 前缀和优化:通过前缀和数组 sum[] 快速计算任意区间的空白数量总和。

  • 滑动窗口:遍历所有可能的连续 H 行区间,找到空白数量总和最大的区间。


代码逻辑流程

1. 初始化

  • 定义常量 N 为 1000010,表示数组的最大大小。

  • 定义 long long 类型的别名 ll,用于处理大整数。

  • 定义差分数组 d[]、原数组 a[] 和前缀和数组 sum[]

2. 输入处理

  • 读取障碍物的尺寸 n 和箱子的高度 h

  • 循环读取每一列的空白区域 [l_i, h_i],并更新差分数组 d[]

    • d[l_i]++:从第 l_i 行开始,空白区域的数量增加 1。

    • d[h_i + 1]--:从第 h_i + 1 行开始,空白区域的影响结束。

3. 计算原数组 a[]

  • 通过差分数组 d[] 计算原数组 a[],表示每一行的空白数量:

    • a[i] = a[i - 1] + d[i - 1]

4. 计算前缀和数组 sum[]

  • 通过原数组 a[] 计算前缀和数组 sum[],表示前 i 行的空白数量总和:

    • sum[i] = sum[i - 1] + a[i]

5. 找到最大空白区域

  • 初始化 ans 为前 h 行的空白数量总和。

  • 使用滑动窗口遍历所有可能的连续 h 行区间,找到空白数量总和最大的区间:

    • ans = max(ans, sum[left + h - 1] - sum[left - 1])

6. 输出结果

  • 计算需要清理的障碍物面积:总障碍物面积 - 最大空白面积

  • 输出结果:cout << (ll)n * h - ans << endl;


代码逻辑总结

  1. 输入处理

    • 读取障碍物的尺寸 n 和箱子的高度 h

    • 读取每一列的空白区域 [l_i, h_i],并更新差分数组 d[]

  2. 差分数组还原

    • 通过差分数组 d[] 计算原数组 a[],表示每一行的空白数量。

  3. 前缀和计算

    • 通过原数组 a[] 计算前缀和数组 sum[],表示前 i 行的空白数量总和。

  4. 滑动窗口查找最大空白区域

    • 遍历所有可能的连续 h 行区间,找到空白数量总和最大的区间。

  5. 输出结果

    • 计算并输出需要清理的最小障碍物面积。


代码优化点

  • 差分数组:将区间更新操作从 O(NH) 优化到 O(N)。

  • 前缀和数组:将区间查询操作从 O(NH) 优化到 O(N)。

  • 滑动窗口:通过滑动窗口遍历所有可能的连续 h 行区间,时间复杂度为 O(N)。


代码适用场景

  • 适用于处理大规模数据(n 和 h 最大为 1000000)。

  • 通过差分数组和前缀和优化,能够高效解决区间更新和查询问题。


通过以上思路和逻辑,代码能够高效地解决推箱子问题,找到需要清理的最小障碍物面积。

三、 1.棋盘 - 蓝桥云课

算法代码: 

#include <bits/stdc++.h>
using namespace std;
const int N=2200;
int a[N][N],d[N][N];
int n,m;void insert(int x1,int y1,int x2,int y2)
{d[x1][y1]++;d[x1][y2+1]--;d[x2+1][y1]--;d[x2+1][y2+1]++;
}int main()
{cin>>n>>m;while(m--){int x1,y1,x2,y2;cin>>x1>>y1>>x2>>y2;insert(x1,y1,x2,y2);}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){a[i][j]=d[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1];cout<<(a[i][j]&1);}cout<<endl;}return 0;
}

代码思路

1. 问题分析

  • 问题描述:给定一个 n x n 的矩阵,初始时所有元素为 0。进行 m 次操作,每次操作将一个子矩阵 [x1, y1] 到 [x2, y2] 内的所有元素加 1。最后输出每个元素的值是否为奇数(1 表示奇数,0 表示偶数)。

  • 核心目标:高效处理多次区间更新操作,并快速查询每个元素的值。

2. 解决思路

  • 二维差分数组:使用二维差分数组 d[][] 来高效记录每次区间更新操作。

  • 前缀和还原:通过二维前缀和还原原数组 a[][],表示每个元素的值。

  • 奇偶性判断:输出每个元素的值是否为奇数。


代码逻辑流程

1. 初始化

  • 定义常量 N 为 2200,表示矩阵的最大大小。

  • 定义原数组 a[][] 和差分数组 d[][]

2. 插入操作函数 insert

  • 定义函数 insert(x1, y1, x2, y2),用于更新差分数组 d[][]

    • d[x1][y1]++:表示从 (x1, y1) 开始的区域增加 1。

    • d[x1][y2 + 1]--:表示从 (x1, y2 + 1) 开始的区域减少 1。

    • d[x2 + 1][y1]--:表示从 (x2 + 1, y1) 开始的区域减少 1。

    • d[x2 + 1][y2 + 1]++:表示从 (x2 + 1, y2 + 1) 开始的区域增加 1。

3. 主函数

  • 读取矩阵的大小 n 和操作次数 m

  • 循环处理每次操作:

    • 读取子矩阵的范围 [x1, y1] 到 [x2, y2]

    • 调用 insert(x1, y1, x2, y2) 更新差分数组 d[][]

4. 还原原数组 a[][]

  • 使用二维前缀和还原原数组 a[][]

    • a[i][j] = d[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1]

    • 这表示 (i, j) 位置的值等于差分数组的值加上左边和上边的值,减去左上角的值。

5. 输出结果

  • 遍历矩阵的每个元素,输出其值是否为奇数:

    • a[i][j] & 1:判断 a[i][j] 的最低位是否为 1(奇数)。


代码逻辑总结

  1. 初始化

    • 定义矩阵大小 n 和操作次数 m

    • 定义原数组 a[][] 和差分数组 d[][]

  2. 插入操作

    • 每次操作调用 insert(x1, y1, x2, y2),更新差分数组 d[][]

  3. 还原原数组

    • 使用二维前缀和还原原数组 a[][]

  4. 输出结果

    • 遍历矩阵的每个元素,输出其值是否为奇数。


代码优化点

  • 二维差分数组:将区间更新操作从 O(N^2) 优化到 O(1)。

  • 二维前缀和:将区间查询操作从 O(N^2) 优化到 O(1)。

  • 奇偶性判断:通过位运算快速判断每个元素的值是否为奇数。


代码适用场景

  • 适用于处理大规模矩阵的多次区间更新操作。

  • 通过二维差分数组和前缀和优化,能够高效解决区间更新和查询问题。


代码示例

输入

4 2
1 1 2 2
2 2 3 3

输出

1 1 0 0
1 0 1 0
0 1 1 0
0 0 0 0

解释

  • 第一次操作将子矩阵 [1, 1] 到 [2, 2] 内的所有元素加 1。

  • 第二次操作将子矩阵 [2, 2] 到 [3, 3] 内的所有元素加 1。

  • 最终输出每个元素的值是否为奇数。


通过以上思路和逻辑,代码能够高效地处理多次区间更新操作,并快速查询每个元素的值是否为奇数。

重点:

        还原数组 a[][] 的方式是基于 二维前缀和 的原理。需要从 差分数组 和 前缀和 的基本概念入手,逐步推导这个公式。


1. 差分数组的作用

差分数组 d[][] 的作用是高效记录区间更新操作。对于二维数组,差分数组的更新规则如下:

  • 对于一个子矩阵 [x1, y1] 到 [x2, y2] 的区间加 1 操作,这些更新操作的作用是:

  • d[x1][y1]++:表示从 (x1, y1) 开始的区域增加 1。

  • d[x1][y2 + 1]--:表示从 (x1, y2 + 1) 开始的区域减少 1。

  • d[x2 + 1][y1]--:表示从 (x2 + 1, y1) 开始的区域减少 1。

  • d[x2 + 1][y2 + 1]++:表示从 (x2 + 1, y2 + 1) 开始的区域增加 1。

通过这些操作,差分数组 d[][] 记录了每个位置的增量。


2. 前缀和的作用

前缀和的作用是通过累加差分数组 d[][] 来还原原数组 a[][]。对于二维数组,前缀和的计算公式为:

a[i][j]=d[i][j]+a[i−1][j]+a[i][j−1]−a[i−1][j−1]

这个公式的含义是:

  • a[i][j] 表示 (i, j) 位置的值。

  • d[i][j] 是 (i, j) 位置的增量。

  • a[i - 1][j] 是 (i - 1, j) 位置的值,表示上方的前缀和。

  • a[i][j - 1] 是 (i, j - 1) 位置的值,表示左方的前缀和。

  • a[i - 1][j - 1] 是 (i - 1, j - 1) 位置的值,表示左上角的前缀和。

通过这个公式,我们可以将差分数组 d[][] 的增量信息累加到原数组 a[][] 中。


3. 公式的推导

为什么这个公式是正确的?我们可以从 容斥原理 的角度来理解。

  • 目标:计算 (i, j) 位置的值 a[i][j]

  • 增量来源

    • d[i][j]:直接贡献给 (i, j) 的增量。

    • a[i - 1][j]:上方的前缀和,包含了 (i - 1, j) 及其左侧的所有增量。

    • a[i][j - 1]:左方的前缀和,包含了 (i, j - 1) 及其上方的所有增量。

    • a[i - 1][j - 1]:左上角的前缀和,被 a[i - 1][j] 和 a[i][j - 1] 重复计算了,需要减去。

因此,公式可以理解为:

a[i][j]=直接增量+上方前缀和+左方前缀和−左上角前缀和a[i][j]=直接增量+上方前缀和+左方前缀和−左上角前缀和


4. 举例说明

假设有一个 3x3 的矩阵,初始时所有元素为 0。我们进行一次区间加 1 操作,范围为 [1, 1] 到 [2, 2]

更新差分数组

  • d[1][1]++

  • d[1][3]--

  • d[3][1]--

  • d[3][3]++

差分数组 d[][] 的值如下:

d[1][1] = 1
d[1][3] = -1
d[3][1] = -1
d[3][3] = 1

还原原数组

通过前缀和公式计算 a[][]

  • a[1][1] = d[1][1] + a[0][1] + a[1][0] - a[0][0] = 1 + 0 + 0 - 0 = 1

  • a[1][2] = d[1][2] + a[0][2] + a[1][1] - a[0][1] = 0 + 0 + 1 - 0 = 1

  • a[2][1] = d[2][1] + a[1][1] + a[2][0] - a[1][0] = 0 + 1 + 0 - 0 = 1

  • a[2][2] = d[2][2] + a[1][2] + a[2][1] - a[1][1] = 0 + 1 + 1 - 1 = 1

最终原数组 a[][] 的值如下:

1 1 0
1 1 0
0 0 0

5. 总结

还原数组 a[][] 的公式:

a[i][j]=d[i][j]+a[i−1][j]+a[i][j−1]−a[i−1][j−1]

是基于 二维前缀和 和 容斥原理 的推导。通过这个公式,我们可以高效地将差分数组 d[][] 的增量信息累加到原数组 a[][] 中,从而还原出每个位置的值。

四、 1.灵能传输 - 蓝桥云课

算法代码: 

#include <iostream>
#include <algorithm>
using namespace std;#define ll long long
#define N 300005ll sum[N], path[N];  // sum[] 存储前缀和,path[] 存储最终调整后的前缀和数组
bool mark[N];        // mark[] 用于标记某个前缀和是否已经被访问int main()
{int n;cin >> n;  // 读取询问组数while(n--){int m;cin >> m;  // 读取每组询问的高阶圣堂武士数量fill_n(mark, N, false);  // 初始化 mark[] 数组为 falsefill_n(sum, N, 0);       // 初始化 sum[] 数组为 0fill_n(path, N, 0);      // 初始化 path[] 数组为 0// 计算前缀和数组 sum[]for(int i = 1; i <= m; i++){cin >> sum[i];  // 读取灵能值sum[i] += sum[i - 1];  // 计算前缀和}ll begin = sum[0], end = sum[m];  // 记录前缀和数组的首尾项if(begin > end){swap(begin, end);  // 如果 begin > end,交换它们的值}sort(sum, sum + m + 1);  // 对前缀和数组进行排序// 找到排序后 begin 和 end 的下标for(int i = 0; i <= m; i++){if(sum[i] == begin){begin = i;  // 找到 begin 的下标break;}}for(int i = m; i >= 0; i--){if(sum[i] == end){end = i;  // 找到 end 的下标break;}}int left = 0, right = m;  // left 和 right 分别指向 path[] 的开头和末尾// 从 begin 开始,每隔一个元素赋值到 path[] 的开头for(int i = begin; i >= 0; i -= 2){path[left++] = sum[i];  // 赋值到 path[] 的开头mark[i] = true;         // 标记该前缀和已被访问}// 从 end 开始,每隔一个元素赋值到 path[] 的末尾for(int i = end; i <= m; i += 2){path[right--] = sum[i];  // 赋值到 path[] 的末尾mark[i] = true;         // 标记该前缀和已被访问}// 将未访问的前缀和按顺序赋值到 path[] 的中间for(int i = 0; i <= m; i++){if(!mark[i]){path[left++] = sum[i];  // 赋值到 path[] 的中间}}ll answer = 0;  // 初始化不稳定度为 0// 计算 path[] 中相邻元素的差值的最大值for(int i = 1; i <= m; i++){answer = max(answer, abs(path[i] - path[i - 1]));  // 更新不稳定度}cout << answer << endl;  // 输出每组询问的不稳定度}return 0;
}

         这段代码的主要目的是解决一个与 ​前缀和​ 和 ​不稳定度​ 相关的问题。以下是代码的详细思路和解释:


代码思路

  1. 问题描述

    • 给定一个长度为 m 的数组,表示高阶圣堂武士的灵能值。
    • 通过调整数组的顺序,使得调整后的数组的前缀和数组的 ​不稳定度​ 最小。
    • 不稳定度定义为前缀和数组中相邻元素的差值的最大值。
  2. 算法选择

    • 使用 ​前缀和​ 和 ​排序​ 来构造满足条件的前缀和数组。
    • 通过 ​贪心策略​ 构造路径,使得相邻元素的差值尽可能小。
  3. 代码结构

    • 读取输入数据,计算前缀和数组。
    • 对前缀和数组进行排序。
    • 构造满足条件的前缀和数组 path[]
    • 计算不稳定度并输出结果。

代码详解

1. 预处理

int n;
cin >> n;  // 读取询问组数
while(n--){int m;cin >> m;  // 读取每组询问的高阶圣堂武士数量fill_n(mark, N, false);  // 初始化 mark[] 数组为 falsefill_n(sum, N, 0);       // 初始化 sum[] 数组为 0fill_n(path, N, 0);      // 初始化 path[] 数组为 0
  • 读取询问组数 n 和每组询问的数组长度 m
  • 初始化 mark[]sum[] 和 path[] 数组。

2. 计算前缀和数组

for(int i = 1; i <= m; i++){cin >> sum[i];  // 读取灵能值sum[i] += sum[i - 1];  // 计算前缀和
}
  • 计算数组的前缀和 sum[],其中 sum[i] 表示数组前 i 个元素的和。

3. 记录首尾项并排序

ll begin = sum[0], end = sum[m];  // 记录前缀和数组的首尾项
if(begin > end){swap(begin, end);  // 如果 begin > end,交换它们的值
}sort(sum, sum + m + 1);  // 对前缀和数组进行排序
  • 记录前缀和数组的首项 sum[0] 和尾项 sum[m]
  • 如果 begin > end,交换它们的值。
  • 对前缀和数组 sum[] 进行排序。

4. 找到首尾项的下标

for(int i = 0; i <= m; i++){if(sum[i] == begin){begin = i;  // 找到 begin 的下标break;}
}
for(int i = m; i >= 0; i--){if(sum[i] == end){end = i;  // 找到 end 的下标break;}
}
  • 在排序后的 sum[] 中找到 begin 和 end 的下标。

5. 构造 path[] 数组

int left = 0, right = m;  // left 和 right 分别指向 path[] 的开头和末尾// 从 begin 开始,每隔一个元素赋值到 path[] 的开头
for(int i = begin; i >= 0; i -= 2){path[left++] = sum[i];  // 赋值到 path[] 的开头mark[i] = true;         // 标记该前缀和已被访问
}// 从 end 开始,每隔一个元素赋值到 path[] 的末尾
for(int i = end; i <= m; i += 2){path[right--] = sum[i];  // 赋值到 path[] 的末尾mark[i] = true;         // 标记该前缀和已被访问
}// 将未访问的前缀和按顺序赋值到 path[] 的中间
for(int i = 0; i <= m; i++){if(!mark[i]){path[left++] = sum[i];  // 赋值到 path[] 的中间}
}
  • 使用 ​贪心策略​ 构造 path[] 数组:
    • 从 begin 开始,每隔一个元素赋值到 path[] 的开头。
    • 从 end 开始,每隔一个元素赋值到 path[] 的末尾。
    • 将未访问的前缀和按顺序赋值到 path[] 的中间。

6. 计算不稳定度

ll answer = 0;  // 初始化不稳定度为 0// 计算 path[] 中相邻元素的差值的最大值
for(int i = 1; i <= m; i++){answer = max(answer, abs(path[i] - path[i - 1]));  // 更新不稳定度
}cout << answer << endl;  // 输出每组询问的不稳定度
  • 遍历 path[],计算相邻元素的差值的最大值,即为不稳定度。
  • 输出结果。

示例运行

假设输入如下:

n = 1
m = 5
灵能值 = [1, 2, 3, 4, 5]

运行代码后,输出为:

3

总结

  • 这段代码通过 ​前缀和​ 和 ​排序​ 解决了不稳定度最小化的问题。
  • 使用 ​贪心策略​ 构造满足条件的前缀和数组,确保相邻元素的差值尽可能小。
  • 代码逻辑清晰,但需要注意数组下标和边界条件的处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/73342.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI+视频监控电力巡检:EasyCVR视频中台方案如何赋能电力行业智能化转型

随着电力行业的快速发展&#xff0c;电力设施的安全性、稳定性和运维效率变得至关重要。传统视频监控系统在实时性、智能化及多系统协同等方面面临严峻挑战。EasyCVR视频中台解决方案作为一种先进的技术手段&#xff0c;在电力行业中得到了广泛应用&#xff0c;为电力设施的监控…

【哈希表与字符串的算法之路:思路与实现】—— LeetCode

文章目录 两数之和面试题01.02.判定是否为字符重排存在重复元素存在重复元素||字母异位词分组最长公共前缀和最长回文子串二进制求和字符串相乘 两数之和 这题的思路很简单&#xff0c;在读完题目之后&#xff0c;便可以想到暴力枚举&#xff0c;直接遍历整个数组两遍即可&…

RabbitMQ入门:从安装到高级消息模式

文章目录 一. RabbitMQ概述1.1 同步/异步1.1.1 同步调用1.1.2 异步调用 1.2 消息中间件1.2.1 概念1.2.2 作用1.2.3 常见的消息中间件1.2.4 其他中间件 1.3 RabbitMQ1.3.1 简介1.3.2 特点1.3.3 方式1.3.4 架构1.3.5 运行流程 二. 安装2.1 Docker 安装 RabbitMQ 三. 简单队列&…

kernel与modules解耦

一、耦合&#xff1a; linux的kernel与modules存在耦合版本匹配&#xff0c;在版本不匹配&#xff08;内核重新编译后&#xff0c;或者驱动模块编译依赖的内核版本跟运行版本不匹配&#xff09;时候&#xff0c;会存在insmod 驱动模块失败的情形&#xff1b; 二、解耦&#xff…

物理约束神经网络(PINN)和有限元方法哪个更接近“真正的物理规律”?还是两者只是不同的数学表达?

物理约束神经网络(Physics-Informed Neural Networks, PINN)和有限元方法(Finite Element Method, FEM)是两种在科学计算和工程模拟中广泛应用的数值方法。PINN 依赖深度学习来近似微分方程的解,并在训练过程中将物理约束作为损失项融入网络,而 FEM 通过将连续介质的物理…

UI程序的std::cout重定向输出到Visual Studio的debug输出窗口

常用代码。 UI程序的std::cout重定向输出到Visual Studio的debug输出窗口 #include <iostream> #include <streambuf> #include <vector> #include <string> #include <afxwin.h> //MFC// 自定义 streambuf 类&#xff0c;用于重定向输出到 Vis…

Python开发合并多个PDF文件

前言 在我们的工作中&#xff0c;可能有以下场景需要用到合并多个PDF&#xff1a; 文档归档&#xff1a;在企业或组织中&#xff0c;常常需要将相关的文档&#xff08;如合同、报告、发票等&#xff09;合并为一个PDF文件&#xff0c;以便于归档和管理。 报告生成&#xff1a;在…

DeepSeek 助力 C++ 开发:探索智能编程新境界

这篇文章就会详细讲讲 DeepSeek 在 C 开发里到底能怎么用&#xff0c;从上面说的写代码、找错误、优化性能&#xff0c;到管理项目这些方面&#xff0c;还会给出好多实际的代码例子&#xff0c;讲讲实际用起来是啥情况。目的就是给那些做 C 开发的人&#xff0c;一份全面又详细…

C#-使用VisualStudio编译C#工程

一.创建csproj文件 二.创建源cs文件 三.生成解决方案 四.运行解决方案 五.VisualStudio功能列表 <1.代码格式化: CtrlKD完成代码整体格式化 <2.窗口布局 窗口->重置窗口布局 <3.引用查找&关联 <4.包管理 <5.日志输出级别 工具->选项->项目解决方案…

Kafka相关的面试题

以下是150道Kafka相关的面试题及简洁回答&#xff1a; Kafka基础概念 1. 什么是Kafka&#xff1f; Kafka是一个分布式、可扩展、容错的发布-订阅消息系统&#xff0c;最初由LinkedIn开发&#xff0c;现为Apache项目。它适用于高吞吐量的场景&#xff0c;如大数据处理和实时数据…

CTF--Web安全--SQL注入之报错注入

CTF–Web安全–SQL注入之报错注入 一、报错注入的概念 用户使用数据库查询语句&#xff0c;向数据库发送错误指令&#xff0c;数据库返回报错信息&#xff0c;报错信息中参杂着我们想要获取的隐私数据。通常在我们在页面显示中找不到回显位的时候&#xff0c;使用报错注入。 二…

深度学习中学习率调整策略

学习率衰减策略是深度学习优化过程中的一个关键因素&#xff0c;它决定了训练过程中学习率的调整方式&#xff0c;从而影响模型收敛的速度和效果。不同的衰减策略在不同的任务和模型上可能有不同的表现&#xff0c;下面从我用到过的几个衰减策略进行记录&#xff0c;后续慢慢跟…

JavaCV

调用摄像头 public class Camera {public static void main(String[] args) throws FrameGrabber.Exception {// 开启抓取器OpenCVFrameGrabber grabber new OpenCVFrameGrabber(0);grabber.start();// 开启窗口CanvasFrame canvasFrame new CanvasFrame("OpenCV Frame…

凝思linux修改mac地址

临时性修改 /sbin/ifconfig eth0 hw ether 00:0C:29:36:97:20

前端UI编程基础知识:基础三要素(结构→表现→行为)

以下是重新梳理的前端UI编程基础知识体系&#xff0c;结合最新技术趋势与实战要点&#xff0c;以更适合快速掌握的逻辑结构呈现&#xff1a; 一、基础三要素&#xff08;结构→表现→行为&#xff09; 1. HTML5 核心能力 • 语义化标签&#xff1a;<header>, <nav&g…

面试题:实现学生管理系统

这是我在以前面试中遇到的一个问题&#xff0c; 面试官说&#xff1a;你能现场实现一个学生管理系统吗&#xff0c;实现对学生的增删查改这4个功能 当时写了半天没写出来.....&#xff0c;所以我在这里记录一下 10分钟实现学生管理系统并实现 增删查改 功能 #include <iostr…

大语言模型基础—语言模型的发展历程--task1

目录 1.语言模型的发展历程 1.1 统计语言模型 1.2 神经语言模型 1.3 预训练语言模型 1.4 大语言模型 1.5 总结 1.6 各阶段对比与演进逻辑 1.语言模型的发展历程 语言模型的发展历程经历了四个主要阶段&#xff1a;统计语言模型、神经语言模型、预训练语言模型和大语言模…

BIG_EVENT

环境准备: 开发: 跨域问题: 只有浏览器才存在跨域问题, 此时浏览器的地址和前端服务一致,所以不存在跨域问题, 但是当浏览器中的js代码需要向8080发送请求时就会由于存在跨域问题而失败. 简单的说前端和浏览器的地址端口是一致的,浏览器只能向前端服务发送请求, 所以可以使用配…

DAY33 贪心算法Ⅱ

122. 买卖股票的最佳时机 II - 力扣&#xff08;LeetCode&#xff09; 想到把整体利润分解为每天的利润&#xff0c;就豁然开朗了。 class Solution { public:int maxProfit(vector<int>& prices) {int result0;for(int i1;i<prices.size();i){resultmax(0,pric…

【Qt】qApp简单介绍

1. 介绍 在Qt中&#xff0c;qApp是一个全局指针&#xff0c;它指向当前的QApplication或QGuiApplication对象。这个全局指针在Qt应用程序中非常有用&#xff0c;因为它可以让你在任何地方访问到应用程序对象。 在C中&#xff0c;全局指针是一个可以在程序的任何地方访问的指针…