NOIP刷题记录(优美值)

一、题目描述

一个长度为n的序列,对于每个位置i的数ai都有一个优美值,其定义是:

找到序列中最长的一段[l,r],满足l<=i<=r,且[l,r]中位数为ai,则r-l+1就是ai的优美值。
我们比较序列中两个位置的数的大小时,以数值为第一关键字,下标为第二关键字比较。这样的话[l,r]的长度只有可能是奇数。
接下来有q个询问,每个询问[l,r]表示查询区间[l,r]内优美值的最大值。

 二、输入格式

第一行输入n;

接下来一行 n 个整数,代表ai;

接下来一行为一个整数q,代表有q个区间

接下来q行,每行两个整数l,r(l<=r),表示区间的左右端点。

三、输出格式

对于每个区间的询问,输出答案。

四、样例输入

8
16 19 7 8 9 11 20 16
8
3 8
1 4
2 3
1 1
5 5
1 2
2 8
7 8

五、样例输出

7
3
1
3
5
3
7
3

六、数据范围与提示

对于30%的数据,满足n,q<=50;

对于70%的数据,满足n,q<=2000;

对于所有数据,满足n<=2000,q<=100000,ai<=200。

七、AC代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long n, a[2000 + 10], q;
long long left[4000 + 10], right[4000 + 10];
long long w[2000 + 10];
inline void yuchuli() {
	scanf("%lld", &n);
	for (register int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
	}
	for (register int i = 1; i <= n; ++i) {
		memset(left, -1, sizeof(left));
		left[n] = 0;
		memset(right, -1, sizeof(right));
		right[n] = 0;
		int cnt = 0;
		for (int j = i - 1; j >= 1; j--) {//对于i以前所有数 
			if (a[j] > a[i]) {//i左边有数比它大 
				cnt++;
			}
			if (a[j] <= a[i]) {//i左边有数比它小 
				cnt--;
			}
			left[n + cnt] = i - j;
		}
		cnt = 0;
		for (register int j = i + 1; j <= n; ++j) {//对于i以后的数 
			if (a[j] >= a[i]) {//i右边有数比它大 
				cnt++;
			}
			if (a[j] < a[i]) {//i右边有数比它小 
				cnt--;
			}
			right[n + cnt] = j - i;
		}
		for (register int j = 1 - i; j <= i - 1; ++j) {
			if (left[n + j] >= 0 && right[n - j] >= 0) {//代表left[n+j]和right[n-j]有赋值 
				w[i] = max(w[i], right[n - j] + 1 + left[n + j]);
			}
		}
	}
}
int f[10000+5][21];
void yuchuli1() {//ST表的预处理 
	for (int i = 1; i <= n; i++) {
		f[i][0] = w[i];
	}
	for (int j = 1; (1 << j) <= n; j++) {
		for (int i = 1; i + (1 << j) - 1 <= n; i++) {
			f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
		}
	}
}
int chazhao(int s, int t) {//ST表的查找 
	int k = 0;
	while ((1 << k) <= t - s + 1) {
		++k;
	}
	k--;
	return max(f[s][k], f[t - (1 << k) + 1][k]);
}
int main() {
	freopen("beautiful.in", "r", stdin);
	freopen("beautiful.out", "w", stdout);
	yuchuli();
	yuchuli1();
	scanf("%lld", &q);
	while (q--) {
		long long l, r;
		scanf("%lld%lld", &l, &r);
		printf("%d\n",chazhao(l,r));
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值