题目大意
给定一个长度为n的序列
1≤n≤2×105,0≤k≤2×105,0≤d≤109,−109≤ai≤109
题目分析
首先要特判d=1的情况不然你会各种挂。
然后考虑一个等差数列的条件:
∙该区间的所有数模d同余,并且不存在相同的数
第一个条件的话,只要是按顺序枚举端点,就可以用指针在总复杂线性的情况下扫出合法区间。
重点考察第二个条件。设左端点是自变量,我们使用线段树维护每一个右端点对应的值。可以发现,只要我从大到小枚举左端点,使用两个单调栈来分别记录一些信息,就可以用一棵支持单点修改和区间加操作的线段树来维护这个值,查询的时候直接在线段树上找最右边的满足条件的位置就好了。
时间复杂度O(nlogn)。
代码实现
#include <algorithm>
#include <iostream>
#include <climits>
#include <cstdio>
#include <cctype>
#include <map>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int INF=INT_MAX;
const int N=200050;
struct segment_tree
{
int tag[N<<2];
int v[N<<2];
void ADD(int x,int y){v[x]+=y,tag[x]+=y;}
void update(int x){v[x]=min(v[x<<1],v[x<<1|1]);}
void clear(int x,int l,int r)
{
if (tag[x])
{
if (l!=r) ADD(x<<1,tag[x]),ADD(x<<1|1,tag[x]);
tag[x]=0;
}
}
void modify(int x,int st,int en,int l,int r,int delta)
{
clear(x,l,r);
if (st==l&&en==r)
{
ADD(x,delta);
return;
}
int mid=l+r>>1;
if (en<=mid) modify(x<<1,st,en,l,mid,delta);
else if (mid+1<=st) modify(x<<1|1,st,en,mid+1,r,delta);
else modify(x<<1,st,mid,l,mid,delta),modify(x<<1|1,mid+1,en,mid+1,r,delta);
update(x);
}
void assign(int x,int y,int l,int r,int val)
{
clear(x,l,r);
if (l==r)
{
v[x]=val;
return;
}
int mid=l+r>>1;
if (y<=mid) assign(x<<1,y,l,mid,val);
else assign(x<<1|1,y,mid+1,r,val);
update(x);
}
int query(int x,int st,int en,int l,int r,int y)
{
clear(x,l,r);
if (v[x]>y) return 0;
if (l==r) return l;
int mid=l+r>>1;
if (st==l&&en==r)
if (v[x<<1|1]<=y) return query(x<<1|1,mid+1,en,mid+1,r,y);
else return query(x<<1,st,mid,l,mid,y);
else
if (en<=mid) return query(x<<1,st,en,l,mid,y);
else if (mid+1<=st) return query(x<<1|1,st,en,mid+1,r,y);
else
{
int ret=query(x<<1|1,mid+1,en,mid+1,r,y);
return ret?ret:query(x<<1,st,mid,l,mid,y);
}
}
}t;
int top[2];
map<int,bool> cnt;
int stack[N][2];
int a[N],b[N];
int nxt[N][2];
int n,K,D,ansl,anslen;
void calc()
{
anslen=0;
for (int i=n,cur=n,ptr=n,lst=-1;i>=1;--i)
{
for (;ptr>i&&cnt[b[i]];cnt[b[ptr--]]=0);
cnt[b[i]]=1;
if (a[i]%D!=lst) lst=a[i]%D,top[0]=top[1]=0,stack[0][0]=stack[0][1]=(cur=i)+1;
a[i]/=D;
t.assign(1,i,1,n,-i);
for (;top[0]&&a[stack[top[0]][0]]>a[i];--top[0]) t.modify(1,stack[top[0]][0],stack[top[0]-1][0]-1,1,n,a[stack[top[0]][0]]-a[i]);
for (;top[1]&&a[stack[top[1]][1]]<a[i];--top[1]) t.modify(1,stack[top[1]][1],stack[top[1]-1][1]-1,1,n,a[i]-a[stack[top[1]][1]]);
int r=t.query(1,i,min(cur,ptr),1,n,K-i);
if (r-i+1>=anslen) anslen=r-i+1,ansl=i;
stack[++top[0]][0]=stack[++top[1]][1]=i;
}
}
void special()
{
anslen=0;
int curlen=0,curl=0;
for (int i=1;i<=n;++i)
{
if (a[i]!=a[i-1])
{
if (curlen>anslen) ansl=curl,anslen=curlen;
curl=i,curlen=0;
}
++curlen;
}
if (curlen>anslen) ansl=curl,anslen=curlen;
}
int main()
{
freopen("kdseq.in","r",stdin),freopen("kdseq.out","w",stdout);
n=read(),K=read(),D=read();
for (int i=1;i<=n;++i) a[i]=b[i]=read()+1000000000;
if (D) calc();
else special();
printf("%d %d\n",ansl,ansl+anslen-1);
fclose(stdin),fclose(stdout);
return 0;
}