T2:
一个长度为 n 的序列,对于每个位置 i 的数 ai 都有一个优美值,其定义是:找到序列中最长的一段 [l,r] ,满足 l≤i≤r,且 [l,r] 中位数为ai(我们比较序列中两个位置的数的大小时,以数值为第一关键字,下标为第二关键字比较。这样的话 [l,r] 的长度只有可能是奇数),r-l+1 就是 i 的优美值。
接下来有 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
#include<bits/stdc++.h>
using namespace std;
int a[2005],big1[2005],sum1[2005],sum2[2005],loc1[20005],loc2[20005];
int n,q,f[2005],fs[2005][2005];
int main(){
//freopen("beautiful.in","r",stdin);
//freopen("beautiful.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i){
memset(loc1,0,sizeof(loc1));
memset(loc2,0,sizeof(loc2));
memset(sum1,0,sizeof(sum1));
memset(sum2,0,sizeof(sum2));
loc1[n]=i;loc2[n]=i;
int min1=n,max1=n,min2=n,max2=n;
for(int j=i-1;j>=1;--j){
if(a[j]>a[i]) sum1[j]=sum1[j+1]+1;
else sum1[j]=sum1[j+1]-1;
loc1[sum1[j]+n]=j;
max1=max(max1,sum1[j]+n);
min1=min(min1,sum1[j]+n);
}
for(int j=i+1;j<=n;++j){
if(a[j]<a[i]) sum2[j]=sum2[j-1]-1;
else sum2[j]=sum2[j-1]+1;
loc2[sum2[j]+n]=j;
max2=max(max2,sum2[j]+n);
min2=min(min2,sum2[j]+n);
}
int ans=0;
for(int j=min1;j<=max1;++j){
if(loc2[2*n-j]!=0) ans=max(ans,loc2[2*n-j]-loc1[j]+1);
}
f[i]=ans; //求优美值,写得有点累赘
}
for(int i=1;i<=n;++i) fs[i][i]=f[i];
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j){
if(f[j]>fs[i][j-1]) fs[i][j]=f[j];
else fs[i][j]=fs[i][j-1];//i到j区间最大值,可以用RMQ
}
scanf("%d",&q);
for(int i=1;i<=q;++i){
int x,y;
scanf("%d%d",&x,&y);
cout<<fs[x][y]<<endl;
}
return 0;
}