Description
我们称一个数列为一个好的k-d数列,当且仅当我们在其中加上最多k个
数之后,数列排序后为一个公差为d的等差数列。
你手上有一个由n个整数组成的数列a。你的任务是找到它的最长连续子
串,使得满足子串为好的k-d数列。
Solution
d
=
0
d=0
d=0先特判。
否则一个区间满足条件,当且仅当:
1、区间内的数
%
d
\%d
%d相等。
2、区间内没有重复的数。
3、
m
a
x
−
m
i
n
d
≤
r
−
l
+
k
{max-min\over d}\le r-l+k
dmax−min≤r−l+k。
把第三个条件再化一下,把原序列每个数变为
÷
d
\div d
÷d向下取整,那么条件变为
m
a
x
−
m
i
n
≤
r
−
l
+
k
max-min\le r-l+k
max−min≤r−l+k。
枚举
r
r
r,第一个条件直接一边扫看向左最多伸到哪里,第二个条件先求出每个位置的数上一次出现位置
p
r
e
i
pre_i
prei,一个区间
[
l
,
r
]
[l,r]
[l,r]没有重复的数就是区间
p
r
e
i
pre_i
prei最大值
<
l
<l
<l,二分+
R
M
Q
RMQ
RMQ即可。
对于第三个条件,我的做法比较复杂,用线段树维护每个位置当前到
r
r
r的最大最小值,询问时就在线段树上二分第一个
m
a
x
−
m
i
n
+
l
≤
r
+
k
max-min+l\le r+k
max−min+l≤r+k的位置。
网上的题解似乎都是用一个单调栈辅助,确实简单了许多,线段树不用维护太多东西,只是一些基本操作。
一开始判断余数相同这个条件,脑抽了用绝对值
%
d
\%d
%d的余数来判断……调了好久……
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=200010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
map<int,int>pos;
int n,k,d,a[Maxn],b[Maxn],pre[Maxn],f[Maxn][18],Log[Maxn];
int query_mx(int l,int r)
{
int t=Log[r-l+1];
return max(f[l][t],f[r-(1<<t)+1][t]);
}
struct Seg{int l,r,lc,rc,c[3],cmx,cmx1,cmn,cmn1,tmx,tmn;}tr[Maxn<<1];
int tot=0;
void wmx(int x,int v)
{
if(v<tr[x].cmx)return;
tr[x].cmx1=tr[x].cmx=v;tr[x].c[2]=tr[x].l+v;tr[x].c[0]=tr[x].c[1]+v;tr[x].tmx=v;
}
void wmn(int x,int v)
{
if(v>tr[x].cmn)return;
tr[x].cmn1=tr[x].cmn=v;tr[x].c[1]=tr[x].l-v;tr[x].c[0]=tr[x].c[2]-v;tr[x].tmn=v;
}
void up(int x)
{
int lc=tr[x].lc,rc=tr[x].rc;
tr[x].cmx=max(tr[lc].cmx,tr[rc].cmx);
tr[x].cmn=min(tr[lc].cmn,tr[rc].cmn);
tr[x].cmx1=min(tr[lc].cmx1,tr[rc].cmx1);
tr[x].cmn1=max(tr[lc].cmn1,tr[rc].cmn1);
for(int i=0;i<3;i++)tr[x].c[i]=min(tr[lc].c[i],tr[rc].c[i]);
}
void down(int x)
{
int t=tr[x].tmx;
if(t!=inf)wmx(tr[x].lc,t),wmx(tr[x].rc,t),tr[x].tmx=inf;
t=tr[x].tmn;
if(t!=inf)wmn(tr[x].lc,t),wmn(tr[x].rc,t),tr[x].tmn=inf;
}
void build(int l,int r)
{
int x=++tot;
tr[x].l=l;tr[x].r=r;tr[x].tmx=tr[x].tmn=inf;
if(l==r)return;
int mid=l+r>>1;
tr[x].lc=tot+1,build(l,mid);
tr[x].rc=tot+1,build(mid+1,r);
}
void w(int x,int p)
{
if(tr[x].l==tr[x].r)
{
tr[x].cmx=tr[x].cmn=tr[x].cmx1=tr[x].cmn1=b[p];
tr[x].c[0]=p;tr[x].c[1]=p-b[p];tr[x].c[2]=p+b[p];
return;
}
int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
down(x);
if(p<=mid)w(lc,p);
else w(rc,p);
up(x);
}
int tmp[30],lt;
void _w(int x,int l,int r,int v,int o)
{
if(tr[x].l==l&&tr[x].r==r)
{
if(o==1)wmx(x,v);
if(o==2)wmn(x,v);
if(o==3)tmp[++lt]=x;
return;
}
int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
down(x);
if(r<=mid)_w(lc,l,r,v,o);
else if(l>mid)_w(rc,l,r,v,o);
else _w(lc,l,mid,v,o),_w(rc,mid+1,r,v,o);
up(x);
}
int V;
int go(int x,int op)
{
if(tr[x].l==tr[x].r)return x;
int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
down(x);
if(op==1)
{
if(tr[lc].c[0]<=V)return go(lc,op);
return go(rc,op);
}
else if(op==2)
{
if(tr[lc].cmn1>=V)return go(lc,op);
return go(rc,op);
}
else
{
if(tr[lc].cmx1<=V)return go(lc,op);
return go(rc,op);
}
}
int main()
{
n=read(),k=read(),d=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
pre[i]=pos[a[i]];pos[a[i]]=i;
}
int ans=1,L=1,R=1,v=1;
if(d==0)
{
for(int i=2;i<=n;i++)
{
if(a[i]==a[i-1])v++;
else v=1;
if(v>ans)ans=v,R=i,L=i-v+1;
}
return printf("%d %d",L,R),0;
}
Log[1]=0;for(int i=2;i<=n;i++)Log[i]=Log[i>>1]+1;
for(int i=1;i<=n;i++)f[i][0]=pre[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
for(int i=1;i<=n;i++)b[i]=(int)floor((double)a[i]/(double)d);
build(1,n);w(1,1);
for(int i=2;i<=n;i++)
{
if((a[i]%d+d)%d==(a[i-1]%d+d)%d)v++;
else v=1;
if(v>1)
{
lt=0;_w(1,i-v+1,i-1,0,3);
int op=(b[i]>b[i-1]);
bool flag=false;
for(int j=lt;j;j--)
{
int x=tmp[j];
if(op==1)
{
if(tr[x].cmx<=b[i])wmx(x,b[i]);
else{V=b[i];int o=go(x,3);_w(1,tr[o].l,tr[x].r,b[i],1);break;}
}
else
{
if(tr[x].cmn>=b[i])wmn(x,b[i]);
else{V=b[i];int o=go(x,2);_w(1,tr[o].l,tr[x].r,b[i],2);break;}
}
}
}
w(1,i);
if(v<=R-L+1)continue;
int l=i-v+1,r=i;bool flag=false;
while(l<=r)
{
int mid=l+r>>1;
if(query_mx(mid,i)<mid)r=mid-1,flag=true;
else l=mid+1;
}
if(!flag)continue;
r++;lt=0;
_w(1,r,i,0,3);V=i+k;
for(int j=1;j<=lt;j++)
{
int x=tmp[j];
if(tr[x].c[0]<=V)
{
int o=go(x,1);
if(i-tr[o].l+1>R-L+1)R=i,L=tr[o].l;
break;
}
}
}
printf("%d %d",L,R);
}