解题思路:
-
输入解析:
- 读取交易数量
m
和查询数量n
。 - 读取包含每笔交易金额的数组
transactions
。 - 读取每个查询,每个查询由两个整数
a
和b
组成,表示需要找到数组中下标范围[a, b]
内的最小交易金额。
- 读取交易数量
-
预处理:
- 稀疏表(Sparse Table)用于区间最小值查询:
- 构建一个二维数组
rmq
,其中rmq[i][j]
存储从下标i
开始,长度为2^j
的区间内的最小交易金额。 - 使用动态规划填充这个表:
rmq[i][0]
直接存储transactions[i]
。- 对于更大的幂次,
rmq[i][j]
计算为min(rmq[i][j-1], rmq[i + 2^(j-1)][j-1])
。
- 构建一个二维数组
- 稀疏表(Sparse Table)用于区间最小值查询:
-
处理查询:
- 对于每个查询
[a, b]
,计算区间长度 (len = b - a + 1
)。 - 使用预计算的
rmq
表快速找到[a, a + len - 1]
区间内的最小值:- 找到最小的幂次
k
,使得2^k <= len
。 - 使用
min(rmq[a][k], rmq[b - 2^k + 1][k])
计算结果。
- 找到最小的幂次
- 对于每个查询
-
输出:
- 将所有查询的结果以空格分隔输出。
C++ 实现代码示例:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
const int MAXN = 100000;
const int LOGMAXN = 17; // log2(MAXN) + 1
int transactions[MAXN];
int rmq[MAXN][LOGMAXN];
void preprocessRMQ(int n) {
// 初始化长度为1的区间的 rmq
for (int i = 0; i < n; ++i) {
rmq[i][0] = transactions[i];
}
// 动态规划填充 rmq 表
for (int j = 1; (1 << j) <= n; ++j) {
for (int i = 0; i + (1 << j) - 1 < n; ++i) {
rmq[i][j] = min(rmq[i][j - 1], rmq[i + (1 << (j - 1))][j - 1]);
}
}
}
int rangeMinimumQuery(int left, int right) {
int j = log2(right - left + 1);
return min(rmq[left][j], rmq[right - (1 << j) + 1][j]);
}
int main() {
int m, n;
cin >> m >> n;
// 读取交易金额数组
for (int i = 0; i < m; ++i) {
cin >> transactions[i];
}
// 预处理 RMQ
preprocessRMQ(m);
// 处理查询
for (int i = 0; i < n; ++i) {
int a, b;
cin >> a >> b;
// 转换为从0开始的索引,因为在RMQ查询中使用
--a; --b;
cout << rangeMinimumQuery(a, b) << " ";
}
cout << endl;
return 0;
}
解释:
- RMQ 的预处理:函数
preprocessRMQ
使用动态规划构建了rmq
表,有效地计算了所有可能区间的最小值。 - 查询处理:函数
rangeMinimumQuery
用于快速找到指定范围内的最小值,利用了预处理的rmq
表来提高查询效率。 - 输出:所有查询的结果会按照题目要求,在一行中用空格分隔输出。
这种方法确保每个查询都能在对数时间内完成,即使对于大量的输入数据也能高效处理。
链接:忠诚 - 洛谷
求关注、点赞、收藏