题意:给定一串数列,求满足ai<=ak<=aj条件(ak不一定是有序的)的最大j-i,即端点为这段序列的最小值和最大值。
思路:二分+RMQ,可以这样做,枚举i,求出比a[i]小的第一个数字的下标r,那么在[i,r]范围内找到最大值的下标k,那么就可以更新答案了。那么为什么在求比a[i]小的第一个数字的时候可以用二分呢?因为rmq数组其实满足单调性的,所以可以二分
吐槽:一开始没看清题目就做..以为是求LIS...无语..
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 50000+100;
int dmax[maxn][20];
int dmin[maxn][20];
int d[maxn];
int mmax(int i,int j)
{
if (d[i]>d[j])
return i;
return j;
}
int mmin(int i,int j)
{
if (d[i]<d[j])
return i;
return j;
}
void initmax(int n)
{
for (int i = 1;i<=n;i++)
dmax[i][0]=i;
for (int j = 1;(1<<j)<=n;j++)
for (int i = 1;i+(1<<j)-1<=n;i++)
dmax[i][j]=mmax(dmax[i][j-1],dmax[i+(1<<(j-1))][j-1]);
}
int getmax(int L,int R)
{
int k = 0;
while ((1<<(k+1)) <= R-L+1)
k++;
return mmax(dmax[L][k],dmax[R-(1<<k)+1][k]);
}
void initmin(int n)
{
for (int i = 1;i<=n;i++)
dmin[i][0]=i;
for (int j = 1;(1<<j)<=n;j++)
for (int i = 1;i+(1<<j)-1<=n;i++)
dmin[i][j]=mmin(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
}
int getmin(int L,int R)
{
int k = 0;
while ((1<<(k+1)) <= R-L+1)
k++;
return mmin(dmin[L][k],dmin[R-(1<<k)+1][k]);
}
int get_r(int i,int l,int r)
{
while (l<r)
{
int m = (l+r)/2;
if (d[i]<d[getmin(l,m)])
l=m+1;
else
r=m;
}
return l;
}
int main()
{
int n,q;
while (scanf("%d",&n)!=EOF)
{
for (int i = 1;i<=n;i++)
scanf("%d",&d[i]);
initmax(n);
initmin(n);
int ans = 0;
for (int i = 1;i<=n;i++)
{
int r = get_r(i,i+1,n);
int k = getmax(i,r);
if (d[i]<d[k])
ans = max(ans,k-i);
}
if (!ans)
printf("-1\n");
else
printf("%d\n",ans);
}
}