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
#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;
}