RMQ问题就是区间最小值问题,这是一个非常经典的题,
由他引申出来的也是不计其数最多的是给出一个区间,然后输入多组区间端点,求输入区间的最小值。
每次用循环来计算一个最小值显然不够快,怎么办呢?
实践中最常用的是Tarjan的 Sparse-Table算法,它的预处理时间是O(nlogn),但是查询只需要O(1),而且常数很小。
它的思想很简单,就是递推+二分的思想。我们先定义一个二维数组d[i][j],
代表从 i 开始,长度为2的j次幂的区间中的最小值
然后写出递推公式
d[i][j]
= min( d[i][j
– 1], d[i
+ (1 << (j - 1))][j
- 1]),
其中1
<< (j - 1) 代表2的 j – 1次幂查询操作很简单,
我们要先求出一个数k 让2的k次幂小于等于R-L+1,
那么d[L][k]与d[R-(1
<< k) + 1][k]就覆盖了整个L到R的区间,读者可自行验证。
现在就可以写出完整的代码了
#include<stdio.h> #include<algorithm> using namespace std; int a[100]; int dp[100][10]; int query(int L, int R){ int k = 0; while (1 << (k + 1) <= R - L + 1) k++; return min(dp[L][k], dp[R - (1 << k) + 1][k]); } int main(){ int n, i, j; scanf("%d", &n); for (i = 1; i <= n; i++){ scanf_s("%d", &a[i]); dp[i][0] = a[i]; } for (i = 1; (1 << i) <= n; i++){ for (j = 1; j + (1 << (i - 1)) <= n; j++){ dp[j][i] = min(dp[j][i - 1], dp[j + (1 << (i - 1))][i - 1]); } } int L, R; scanf("%d%d", &L, &R); printf("%d\n", query(L, R)); return 0; }
附上一个相关练习[南阳oj上的一道题
很好](http://acm.nyist.net/JudgeOnline/problem.php?pid=119)
时间: 2024-11-01 15:02:11