例题3.8 频繁出现的数值 UVa11235

该博客详细介绍了RMQ问题在UVa11235题目中的应用。通过游程编码(RLE)处理非降序数组,将数组转化为(-1,1),(1,2),(2,3),(4,1)等形式,并使用Left[pos],Right[pos]记录段的端点。查询(L,R)时,答案由三部分最大值组成,结合Sparse-table算法求解。特殊情况是当L和R在同一段时,答案直接计算。" 100010192,8682509,深度解析:Mask R-CNN在自动驾驶中的应用,"['自动驾驶', '人工智能', '图像处理', '深度学习', '计算机视觉']
摘要由CSDN通过智能技术生成

1.题目描述:点击打开链接

2.解题思路:本题属于RMQ问题。注意到整个数组是非降序的,所有相等的元素都会聚在一起,这样就可以把整个数组进行游程编码(Run Lengh Encodeing RLE)。比如-1,1,2,2,2,4就可以表示为(-1,1),(1,2),(2,3),(4,1)。其中(a,b)表示有b个连续的a。本题中,用Left[pos],Right[pos]分别表示位置pos所在段的左右端点的位置。p[i]表示第i段的元素个数。那么每次查询(L,R)的结果为以下三部分的最大值:从L到Right[L]处的元素个数,从Left[R]到R的元素个数,区间Right[L]+1到Left[R]-1之间的最大值,其中这段区间可以利用Sparse-table算法解决。特殊情况:如果L和R在同一段,那么答案就是R-L+1。

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

#define N 100000+10
int A[N];
int n, q, e;
int C[N][20], Left[N], Right[N];
int p[N];
void init()
{
	for (int i = 0; i < n; i++)
		C[i][0] = p[i];
	for (int j = 1; (1 << j) <= n;j++)
	for (int i = 0; i + (1 << j) < n; i++)
		C[i][j] = max(C[i][j - 1], C[i + (1 << j - 1)][j - 1]);
}
int Query(int L, int R)
{
	int k = log((double)R - L + 1) / log(2.0);
	return max(C[L][k], C[R - (1 << k) + 1][k]);
}
int main()
{
	//freopen("t.txt", "r", stdin);
	while (~scanf("%d", &n) && n)
	{
		scanf("%d", &q);
		for (int i = 0; i < n; i++)
			scanf("%d", A + i);
		memset(p, 0, sizeof(p));
		int pos = 0;
		Left[0] = 0, p[0] = 1;
		for (int i = 1; i < n; i++)
		{
			if (A[i] == A[i - 1])
				p[i] = p[i - 1] + 1;//数组p统计每段的个数,先进行累加,最后分别以每段最后的统计结果为准,进行统一
			else
			{
				pos = i;
				p[i] = 1;
			}
			Left[i] = pos;
		}
		pos = n - 1, Right[pos] = pos;
		for (int i = n - 2; i >= 0; i--)
		{
			if (A[i] == A[i + 1])
				p[i] = p[i + 1];//以每段的最后一个数为准,将个数统一
			else pos = i;
			Right[i] = pos;
		}
		init();
		while (q--)
		{
			int s, t;
			scanf("%d%d", &s, &t);
			s--, t--;
			int ans = 0;
			if (A[s] == A[t])ans = t - s + 1;//特殊情况
			else
			{
				if (Right[s] + 1 < Left[t] - 1)//三段的最大值
					ans = Query(Right[s] + 1, Left[t] - 1);
				ans = max(ans, Right[s] - s + 1);
				ans = max(ans, t - Left[t] + 1);
			}
			printf("%d\n", ans);
		}
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值