题目3 : 等差子数列
题意:中文题。
思路:关键在于连续。一个数要么和前两个构成等差,长度加一;要么和前一个构成新的等差,长度为2,前提是前一个存在。那么我们可以写出每个数的位置所能达到的最长的等差连续子序列。
如:
1 2 3 5 7 9
对应:1 2 3 2 3 4
这样貌似只需查询区间最值即可,但切勿忽略一个问题:如果上述数列查询的区间为[2,4],ans应为2而不是3。这种情况id=3的位置实际贡献应该是2.
假设区间某一位置id的连续最长等差子序列长度为ma:
① ma<=id-l+1 : ans=ma(此序列完全包含在所查询区间内)
② ma>id-l+1 : ans=id-l+1 ???这个ans只能代表前面一小段的贡献,而后面的可能有更长的。
比如: 1 2 3 4 1 2 3,查询区间[3,7],正确答案应该是3.
所以在②的情况下,还需要查询后面一小段的最大值即可,这一小段能保证全在查询区间内。然后ANS=max(id-l+1,post_max).
我们在查询的时候需要知道最大值及其位置。也就是很简单的线段树,但很久没写代码了调了半天。
//头文件已删
#define sc(x) scanf("%d",&x)
#define pd(x) printf("%d\n",x)
#define cls(a,x) memset(a,x,sizeof(a))
const double eps=1e-8;
const double PI=acos(-1.0);
const int INF=1e9+10;
const int mod=1e9+7;
const int N=2e5+10;
int c[N],b[N],n,m;
//char s[N];
struct node
{
int l,r;
int ma,id;
}a[N<<2];
void build(int l,int r,int k)
{
a[k].l=l,a[k].r=r,a[k].ma=0,a[k].id=0;
if(l==r) return ;
int mid=(l+r)>>1;
build(l,mid,2*k);
build(mid+1,r,2*k+1);
}
void in(int pos,int num,int k)
{
if(a[k].l==a[k].r&&a[k].l==pos)
{
a[k].ma=num;
a[k].id=pos;
return ;
}
int mid=(a[k].l+a[k].r)>>1;
if(pos<=mid) in(pos,num,2*k);
else in(pos,num,2*k+1);
if(a[k*2+1].ma>=a[k*2].ma) a[k].ma=a[k*2+1].ma,a[k].id=a[k*2+1].id;
else a[k].ma=a[k*2].ma,a[k].id=a[k*2].id;
}
int id,maxx;//得到最大值,与最大值的位置
void Q1(int l,int r,int k)
{
if(l>r) return ;
if(a[k].l==l&&a[k].r==r)
{
// printf("l=%d r=%d maxx=%d id=%d\n",l,r,a[k].ma,a[k].id);
if(a[k].ma>maxx)
{
maxx=a[k].ma;
id=a[k].id;
}
else if(a[k].ma==maxx&&a[k].id>id) id=a[k].id;
return ;
}
int mid=(a[k].l+a[k].r)>>1;
if(r<=mid) Q1(l,r,2*k);
else if(l>mid) Q1(l,r,2*k+1);
else
{
Q1(l,mid,2*k);
Q1(mid+1,r,2*k+1);
}
}
int main()
{
while(~sc(n))
{
sc(m);
build(1,n,1);
b[0]=0;
int la=0;
for(int i=1; i<=n; i++)
{
sc(c[i]);
if(i<=2)
{
if(i==2) la=c[i]-c[i-1];
b[i]=i;
}
else
{
if(c[i]-c[i-1]==la) b[i]=max(2,b[i-1]+1);
else la=c[i]-c[i-1],b[i]=2;
}
}
for(int i=1; i<=n; i++)in(i,b[i],1);// printf("%d%c",b[i],i==n?'\n':' '),
int l,r;
while(m--)
{
sc(l);
sc(r);
if(l>r) swap(l,r);
if(r-l+1<=2) printf("%d\n",r-l+1);
else
{
maxx=0,id=0;//先求出最大值及其位置
Q1(l,r,1);
// printf("ma=%d id=%d\n",maxx,id);
if(maxx<=id-l+1) printf("%d\n",maxx);
else
{
int now_ma=id-l+1;//只能有这么多的贡献
maxx=0;
// printf("id+1=%d r=%d\n",id+1,r);
Q1(id+1,r,1);
printf("%d\n",max(now_ma,maxx));
}
}
}
}
}
//6 2
//1 2 3 5 7 9
//2 6
//1 4
//
//7 8
//1 2 3 4 1 2 3
//2 6