题意:给定$a_{1\cdots n}$,让你求出一个最长的子串$a_{l\cdots r}$,使得这个子串加上最多$k$个数字并排序后是一个公差为$d$的等差数列
首先$d=0$就是最长连续相等段,扫一遍解决
然后显然$a_{l\cdots r}$都是模$d$同余的,我们不妨对模$d$的余数不同的段分开处理
把每个数先$+10^9$(让它变为非负)再除以$d$,转化为$d=1$的问题
那么题目的限制条件就是$\mathop\max\limits_{i=l}^ra_i-\mathop\min\limits_{i=l}^ra_i+1\leq r-l+1+k$且$a_{l\cdots r}$中没有重复元素
所以整个算法的大致思路就是,对$a_{l\cdots r}$,从大到小枚举$i\in[l,r]$,找到最大的$j\in[l,r]$满足$\mathop\max\limits_{k=i}^ja_k-\mathop\min\limits_{k=i}^ja_k-r\leq k-l$且$a_{i\cdots j}$中没有相同元素
没有相同元素:直接用一个map存每个数上一次出现的位置,相应左移$r$即可
对于这个不等式,注意到$f(r)=\mathop\max\limits_{i=l}^ra_i$是单调不减的,所以我们可以用一个单调栈存当前区间内对于不同的$j$,对上式有贡献的$a_i$(即从左往右扫,会令当前最大值变化的那些$a_i$),$\min$同理,当左端点移动时,入栈出栈的同时用线段树维护$\max-\min$即可,对于$-r$,建线段树时第$i$位的初值赋为$-i$即可,我们只需要在线段树上二分找到最右的$\leq k-i$的值即可
#include<stdio.h>
#include<map>
using namespace std;
int mn[800010],ad[800010];
void add(int x,int v){
mn[x]+=v;
ad[x]+=v;
}
void pushdown(int x){
if(ad[x]){
add(x<<1,ad[x]);
add(x<<1|1,ad[x]);
ad[x]=0;
}
}
void pushup(int x){mn[x]=min(mn[x<<1],mn[x<<1|1]);}
void build(int l,int r,int x){
if(l==r){
mn[x]=-l;
return;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
pushup(x);
}
void modify(int L,int R,int v,int l,int r,int x){
if(L<=l&&r<=R)return add(x,v);
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid)modify(L,R,v,l,mid,x<<1);
if(mid<R)modify(L,R,v,mid+1,r,x<<1|1);
pushup(x);
}
int query(int L,int R,int v,int l,int r,int x){
if(mn[x]>v)return 0;
if(l==r)return l;
pushdown(x);
int mid=(l+r)>>1,res;
if(R>mid){
res=query(L,R,v,mid+1,r,x<<1|1);
if(res)return res;
}
if(L<mid){
res=query(L,R,v,l,mid,x<<1);
if(res)return res;
}
return 0;
}
map<int,int>pos;
int a[200010],s1[200010],s2[200010],n,k,d,t1,t2,L,R;
void solve(int l,int r){
if(l==r)return;
int i,tr,res;
for(i=l;i<=r;i++)a[i]=a[i]/d+1;
tr=r+1;
pos.clear();
t1=t2=0;
s1[0]=s2[0]=r+1;
for(i=r;i>=l;i--){
if(pos.count(a[i]))tr=min(tr,pos[a[i]]);
while(t1&&a[i]>a[s1[t1]]){
modify(s1[t1],s1[t1-1]-1,-a[s1[t1]],1,n,1);
t1--;
}
t1++;
s1[t1]=i;
modify(s1[t1],s1[t1-1]-1,a[i],1,n,1);
while(t2&&a[i]<a[s2[t2]]){
modify(s2[t2],s2[t2-1]-1,a[s2[t2]],1,n,1);
t2--;
}
t2++;
s2[t2]=i;
modify(s2[t2],s2[t2-1]-1,-a[i],1,n,1);
res=query(i,tr-1,k-i,1,n,1);
if(res-i>R-L||(res-i==R-L&&i<L)){
L=i;
R=res;
}
pos[a[i]]=i;
}
}
int main(){
int i,l,r;
scanf("%d%d%d",&n,&k,&d);
for(i=1;i<=n;i++){
scanf("%d",a+i);
a[i]+=1000000000;
}
L=R=1;
if(d==0){
for(l=1;l<=n;l=r){
for(r=l;r<=n&&a[r]==a[l];r++);
if(r-l>R-L+1){
L=l;
R=r-1;
}
}
printf("%d %d",L,R);
return 0;
}
build(1,n,1);
L=R=1;
for(l=1;l<=n;l=r){
for(r=l;r<=n&&a[l]%d==a[r]%d;r++);
solve(l,r-1);
}
printf("%d %d",L,R);
}