CF407E k-d-sequence
Description
给定序列 \({a_n}\),求最长的区间,使得至多添加 \(k\) 个数后,重新排序后是一个公差为 \(d\) 的等差数列。
Solution
先特判掉 \(d=0\) 的情况,添数是无用的,只需要求最长的相同的段即可。
\(d\neq 0\) ,由于是等差数列,所以\(\bmod d\) 的值应该相同,先预处理出膜 \(d\) 值相同的一段,然后提出来单独考虑。
一段区间合法当且仅当值域连续,无重复,并且至的个数小于等于区间长度加 \(k\)。
无重复只需要移动左端点,后面的限制可以列成
\[max-min+1\leq (r-l+1+k)*d
\]
只需要找到满足条件的最小的 \(l\) 即可,容易发现可以用单调栈和线段树维护。
#include<stdio.h>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
const int N=2e5+7;
int n,k,d;
int a[N],v[N],c[N],ansl,ansr,ans,t[N<<2],tag[N<<2];
int tp1,tp2,st1[N],st2[N];
map<int,int> b;
#define lid id<<1
#define rid id<<1|1
void Add(int id,int val){t[id]+=val,tag[id]+=val;}
void pd(int id){if(tag[id])Add(lid,tag[id]),Add(rid,tag[id]),tag[id]=0;}
int L,R,Val;
void modify(int id,int lf,int rf){
if(L<=lf&&rf<=R) Add(id,Val);
else{
pd(id); int mid=(lf+rf)>>1;
if(L<=mid) modify(lid,lf,mid);
if(R>mid) modify(rid,mid+1,rf);
t[id]=min(t[lid],t[rid]);
}
}
int check(int id,int lf,int rf){
if(lf==rf) return lf;
pd(id); int mid=(lf+rf)>>1;
if(t[lid]<=Val) return check(lid,lf,mid);
else return check(rid,mid+1,rf);
}
int query(int id,int lf,int rf){
if(L<=lf&&rf<=R)
return t[id]<=Val? check(id,lf,rf):-1;
pd(id); int mid=(lf+rf)>>1,ret=-1;
if(L<=mid) ret=query(lid,lf,mid);
if(~ret) return ret;
return R>mid? query(rid,mid+1,rf):-1;
}
inline void calc(int l,int r){
int hd=l;
st1[0]=st2[0]=l-1,tp1=tp2=0;
for(int i=l;i<=r;i++){
b[v[i]]++;
while(b[v[i]]>1) b[v[hd]]--,hd++;
while(tp1&&v[st1[tp1]]>=v[i])
Val=v[st1[tp1]]-v[i],L=st1[tp1-1]+1,R=st1[tp1],modify(1,1,n),tp1--;
while(tp2&&v[st2[tp2]]<=v[i])
Val=v[i]-v[st2[tp2]],L=st2[tp2-1]+1,R=st2[tp2],modify(1,1,n),tp2--;
st1[++tp1]=i,st2[++tp2]=i;
L=R=Val=i,modify(1,1,n);
L=hd,R=i,Val=i+k; int x=query(1,1,n);
if(i-x+1>ans) ansl=x,ansr=i,ans=i-x+1;
}
for(int i=hd;i<=r;i++) b[v[i]]=0;
}
int main(){
n=read(),k=read(),d=read();
if(!d){
int l=1,r=1;
for(int i=1,tot=0,ans=0,lt=0;i<=n;i++){
int x=read();
if(x==lt) tot++;
else tot=1;
if(tot>ans) ans=tot,r=i,l=i-tot+1;
lt=x;
}
printf("%d %d",l,r);
}else{
for(int i=1,l=1;i<=n+1;i++){
if(i!=n+1)
a[i]=read(),c[i]=(a[i]%d+d)%d,v[i]=(a[i]-c[i])/d;
else c[i]=-1;
if(i!=1&&c[i]!=c[i-1]) calc(l,i-1),l=i;
}
printf("%d %d",ansl,ansr);
}
}