校内模拟CSP-S T2

beautiful

DESCRIPTION:

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

INPUT:

第一行输入n 接下来n 个整数,代表ai 接下来Q,代表有Q 个区间接下来Q 行,每行
两个整数 l, r 表示区间的左右端点

OUTPUT:

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

SAMPLE INPUT:

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

SAMPLE OUTPUT:

7
3
1
3
5
3
7
3

数据范围:

30%: N,Q<=50
70%:N,Q<=2000
100%:N<=2000,Q<=100000,ai<=200
对于所有数据,满足n <= 2000, Q <= 100000, ai <= 200

  • 分析思路

  • == 看数据范围 == n,Q范围明显 O ( n 2 ) O(n^2) 预处理 O ( 1 ) O(1) 查询,那么就是纯RMQ+ST了
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e3+10;
int n;
 /*假设要查询的区间为 [ l, r ],我们用 L 表示区间 [ l , r ] 的长度,即 L = r - l + 1,下面用 k 表示 log L
 其中查询的话,区间长度 L 不一定刚好是 2 的多少次方,又因为 log L 是向下取整,那么 2^k 就有可能小于 L,这样的话,我们就不能直接用 f [ l ][ k ] 来表示答案,不然的话会有遗漏
正确的做法是我们就从 l 往右取 2^k 个(即 f [ l ][ k ]),从 r 往左取 2^k 个(即?f [ r - ( 1 << k ) + 1 ][ k ]),
这样就能保证区间 [ l , r ] 都被访问到了,重复计算的不用担心,这是计算最值而不是求和
 那么答案answer = max { f [ l ][ k ] , f [ r - ( 1 << k ) + 1 ][ k ]}*/
inline int read() {
    int cnt = 0;
    int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
    cnt *= f;
    return cnt;
}
int a[N],v[N],st[N][25];//ST[N][log 2 N]  
int s[N<<1];//s代表状态
inline int preRMQ(int l,int r){//预处理最大值 
	int j=0;
	while((1<<j)<=(r-l+1)){
		j++;
	}
	j--;
	return max(st[l][j],st[r-(1<<j)+1][j]);//数列中下标在[i,i+2的i次方-1]最大值 
}
signed main(){
	freopen("beautiful.in","r",stdin);
	freopen("beautiful.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
	}
	for(int i=1;i<=n;i++){
		memset(s,-1,sizeof(s));
		s[N]=i;// 每个i为一个状态 
		int q=0;
		for(int j=i-1;j>=1;j--){
			if(a[j]<=a[i]){
				q--;
				s[N+q]=j;//防止下标出界 
			}
			else{
				q++;s[N+q]=j;
			}
		}
		q=0;v[i]=i-s[N]+1;//状态长度 
		for(int j=i+1;j<=n;j++){
			if(a[i]<=a[j]){
				q++;//记录比他小的值的个数 
				if(s[N-q]!=-1){//i状态没有被重新更改 
					v[i]=max(v[i],j-s[N-q]+1);
				}
			}
			else{
				q--;
				if(s[N-q]!=-1){
					v[i]=max(v[i],j-s[N-q]+1);
				}
			}
		}
		st[i][0]=v[i];//初始化 st[i][0]=A[i] 
	}
	for(int j=1;(1<<j)<=n;j++){
		for(int i=1;i+(1<<j)-1<=n;i++){
			st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);//处理ST表 
		}
	}
	int l,r,q;
	q=read();
	for(int i=1;i<=q;i++){
		l=read();r=read();
		printf("%d\n",preRMQ(l,r));
	}
	return 0;
}
发布了37 篇原创文章 · 获赞 11 · 访问量 1938

猜你喜欢

转载自blog.csdn.net/weixin_42750325/article/details/101996171
今日推荐