试图理解这个解决方案
Trying to understand this solution
我试图解决一个问题,我遇到了一些我未能解决的障碍,从这里开始是问题: 代码部队 - 817D
现在我尝试暴力破解它,对我可以生成的数组的每个段使用基本的 get min 和 max,然后跟踪它们,我减去它们并将它们加在一起以获得最终的不平衡,这看起来不错,但它给了我一个超出的时间限制,因为暴力强制 n*(n+1)/2 个给定 n 的数组子段为 10^6, 所以我只是没有绕过它,在几个小时没有得到任何新想法之后,我决定看到一个老实说我什么都听不懂的解决方案:/,这是解决方案:
#include <bits/stdc++.h>
#define ll long long
int a[1000000], l[1000000], r[1000000];
int main(void) {
int i, j, n;
scanf("%d",&n);
for(i = 0; i < n; i++) scanf("%d",&a[i]);
ll ans = 0;
for(j = 0; j < 2; j++) {
vector<pair<int,int>> v;
v.push_back({-1,INF});
for(i = 0; i < n; i++) {
while (v.back().second <= a[i]) v.pop_back();
l[i] = v.back().first;
v.push_back({i,a[i]});
}
v.clear();
v.push_back({n,INF});
for(i = n-1; i >= 0; i--) {
while (v.back().second < a[i]) v.pop_back();
r[i] = v.back().first;
v.push_back({i,a[i]});
}
for(i = 0; i < n; i++) ans += (ll) a[i] * (i-l[i]) * (r[i]-i);
for(i = 0; i < n; i++) a[i] *= -1;
}
cout << ans;
}
我尝试跟踪它,但我一直想知道为什么使用向量,我得到的唯一想法是他想将向量用作堆栈,因为它们的行为相同(几乎),但事实上我什至不知道为什么我们需要一个堆栈在这里和这个方程ans += (ll) a[i] * (i-l[i]) * (r[i]-i);
真的让我感到困惑,因为我不知道它来自哪里。
嗯,这是一个计算的野兽。我必须承认,我也不完全理解它。蛮力解决方案的问题在于,您必须重新计算值或重新计算。
在一个稍作修改的示例中,您计算输入的以下值2, 4, 1
(我按"距离"重新排序)
[2, *, *] (from index 0 to index 0), imbalance value is 0; i_min = 0, i_max = 0
[*, 4, *] (from index 1 to index 1), imbalance value is 0; i_min = 1, i_max = 1
[*, *, 1] (from index 2 to index 2), imbalance value is 0; i_min = 2, i_max = 2
[2, 4, *] (from index 0 to index 1), imbalance value is 2; i_min = 0, i_max = 1
[*, 4, 1] (from index 1 to index 2), imbalance value is 3; i_min = 2, i_max = 1
[2, 4, 1] (from index 0 to index 2), imbalance value is 3; i_min = 2, i_max = 1
where i_min and i_max are the indices of the element with the minimum and maximum value.
For a better visual understanding, i wrote the complete array, but hid the unused values with *
因此,在最后一种情况下[2, 4, 1]
,bruteforce会查找所有值的最小值,这不是必需的,因为您已经通过计算[2,4]
和[4,1]
来计算问题的子空间的值。但是仅比较值是不够的,您还需要跟踪最小和最大元素的索引,因为它们可以在下一步计算[2, 4, 1]
时重用。
这背后的想法是一个称为动态规划的概念,其中计算结果被存储以供再次使用。通常,您必须在速度和内存消耗之间进行选择。
所以回到你的问题,这是我的理解:
- 数组
l
和r
用于存储当前数组左侧或右侧最大数量的索引 - 向量
v
用于查找大于当前数字(a[i]
)的最后一个数字(及其索引)。它跟踪上升的数字序列,例如,对于输入5,3,4
首先存储5
,然后存储3
,当4
到来时,弹出 3,但需要索引 5(存储在l[2]
中) - 然后是这个花哨的计算(
ans += (ll) a[i] * (i-l[i]) * (r[i]-i)
)。最大(在第二次运行中是最小值)元素的存储索引与值一起计算a[i]
现在对我来说没有多大意义,但似乎有效(抱歉)。 - 最后,数组
a
中的所有值都乘以-1
,这意味着,旧的最大值现在是最小值,并且再次进行计算(在 j 上第二次运行外部 for 循环)
最后一步(a
乘以-1
)和 j 上的外部 for 循环不是必需的,但这是一种重用代码的优雅方式。
希望这有所帮助。
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- 计算每个节点的树高,帮助我解释这个代码解决方案
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- visual c++,如何获取解决方案目录中的代码
- 有没有办法在远程设备上打开和编辑visual Studio 2017解决方案
- C++Matching Brackets 2解决方案不起作用
- 在 ubuntu3 上C++ goto 定义有什么解决方案吗16.04?
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的固定时间步长与增量时间和插值的解决方案是错误的吗?
- 无法在问题解决方案中执行输出逻辑
- 最大的回文产品 - 程序未运行,编写解决方案但无法理解问题
- 从预序遍历构造 bst 的 c++ 和 python 解决方案之间的区别
- 在一个解决方案中针对第三方静态库 (Creo) 的不同版本(版本)进行构建
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 使用 Git 处理 C++ Visual Studio 2019 解决方案的外部依赖项源代码管理的最佳方法是什么?
- N-queen问题:无法弄清楚为什么我的解决方案不起作用
- 从排序数组中删除重复项,具有不同代码方式的相同解决方案具有不同的输出
- 使用XOR查找O(n)-解决方案中的两个字符串是否为变位符
- Dll在同一解决方案中从 c# 项目导入到 c++ 项目