RMQ问题

来源:互联网 发布:华夏域名注册 编辑:程序博客网 时间:2024/06/05 09:51

BMQ问题就是在一系列连续的数中,找出一个区间内最小的数,基本思路就是用d[i][j]表示从i开始,长度为2^j的一段元素中的最小值,直接先递推预处理,时间是O(nlogn),查找就O(1)

基本模板:

#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int maxn = 10000;int d[maxn][maxn];void RMQ_init(int a[], int n){for (int i = 0; i < n; i++)d[i][0] = a[i];for(int j=1;(1<<j)<=n;j++)for (int i = 0; i + (1 << j)<= n; i++){d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);}}int RMQ(int L, int R){int k = 0;while ((1 << (k + 1)) <= R - L + 1)k++;return min(d[L][k], d[R - (1 << k) + 1][k]);}int main(){int n;int a[maxn];scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%d", &a[i]);RMQ_init(a,n);printf("%d\n", RMQ(1, 7));return 0;}

例题8 UVa11235

题意:
看白书
要点:
一开始先进行游码编程,可以看出最左边和右边是没有办法进行预处理的,因为可能只截取了一半,所以我们将两个边界l,r的左右边界记录下来特殊处理,中间的直接RMQ即可。

#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int maxn = 100005;int coun[maxn], num[maxn], Left[maxn], Right[maxn];int tot,n,q,a,last;int dp[maxn][25];void RMQ_init(){for (int i = 1; i <= tot; i++) dp[i][0] = coun[i];for (int j = 1; (1 << j) <= tot; j++)for (int i = 1; i + (1 << j) <= tot; i++)dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);}int RMQ(int L, int R){if (L > R)return 0;int k = 0;while ((1 << (k + 1)) <= R - L + 1)k++;return max(dp[L][k], dp[R - (1 << k) + 1][k]);}int main(){while (~scanf("%d", &n)&&n){scanf("%d", &q);tot = 0;memset(num, 0, sizeof(num));memset(coun, 0, sizeof(coun));memset(Left, 0, sizeof(Left));memset(Right, 0, sizeof(Right));memset(dp, 0, sizeof(dp));for (int i = 1; i <= n; i++){scanf("%d", &a);if (i == 1){tot++;Left[tot]++;last = a;}if (last == a){num[i] = tot;Right[tot]++;coun[tot]++;}else{num[i] = ++tot;coun[tot]++;Left[tot] = Right[tot] = i;last = a;}}RMQ_init();int l, r;for (int i = 1; i <= q; i++){scanf("%d%d", &l, &r);if (num[l] == num[r])printf("%d\n", r - l + 1);elseprintf("%d\n", max(RMQ(num[l] + 1, num[r] - 1), max(r-Left[num[r]] + 1, Right[num[l]] - l + 1)));}}return 0;}


0 0
原创粉丝点击