[jzoj4665][CF407E]k-d-sequence

来源:互联网 发布:unity3d小球滚动 编辑:程序博客网 时间:2024/06/01 10:36

题目大意

给你一个长度为n的序列a[],两个参数k,d,求序列最长的一段,使得这一段所有的数升序排序后最多再加上k个任意的数,可以构成公差为d的等差数列。输出这一段的两端。
n<=2*10^5, 0<=k<=2*10^5, d,|a[i]|<=10^9

分析

首先有个很显然的结论嘛,答案的那一段区间所有数,两两之间的差都是d的倍数,而且互不相同。那么前者等价于相邻的差是d的倍数,于是乎我们可以把原序列切成许多段,每一段的数相邻的差都是d的倍数。
后者可以设mxright[x]表示最大的满足a[x~mxright[x]]互不相同的值,求答案的时候限制一下就好了。
现在考虑一段上怎么做。
为了看起来好看,激发我们的灵感,我们可以先处理一下数据。对于一段每个数a[x],令a[x]=(a[x]-min)/d+1,min即为这一段的最小值。
接下来怎么做?二分长度?不行,不满足二分性质。
考虑一下暴力如何求解先吧!枚举左右端点l,r,满足什么样的条件可以更新答案呢?
即max{a[l~r]}-min{a[l~r]}+1≤r-l+1+k。

而做这些题的套路,一般是枚举一个左端点,看看合法最远右端点在哪里。
我们化一下上面的式子,max{a[l~r]}-min{a[l~r]}-r≤k-l
这样右边就只与左端点有关了。
我们考虑枚举左端点l。这时设mx[r]=max{a[l~r]},mn[r]=min{a[l~r]},很容易发现mx是不下降的,mn是不上升的,是不是可以维护一下他们呢?设b[r]=mx[r]-mn[r]-r;看一下怎么维护它,加入能维护,那么我们只要找最大的r,满足b[r]≤k-l。
倒着枚举左端点,这样可以让mx只会变大而不缩小,更好维护;mn同理。考虑l变成l-1会发生什么?就是mx(mn)中,大于(小于)a[l-1]的,全部变为a[l-1]。哎,我们发现会出现一块一块的东西,以后修改的时候不就可以区间修改了?因此我们用栈记录每种值出现的一块的位置,这样到时候更新mx(mn)就很方便了,每次弹出一块,区间加(减)。事实上,我们只用线段树维护b就好了。
那么整理一下做法:枚举右端点l,用线段树维护b数组,区间加减,区间位置由栈来维护。寻找最大r满足b[r]≤k-l,且r≤mxright[l]。时间复杂度O(nlogn)

代码

打的时候生病了,很乱。

#include<cstdio>#include<algorithm>#include<cstring>#include<map>using namespace std;typedef long long ll;#define fo(i,j,k) for(i=j;i<=k;i++)#define fd(i,j,k) for(i=j;i>=k;i--)const int M=200005,mx=1e9+7,N=1e8+7;struct rec{    int mn,tag;}tr[M*5];int a[M],n,K,d,sta1[M],sta2[M],b[M],t1,t2,i,j,k,l,r,L,R,tt,mn,ans,x,maxr[M],dur;//store posmap<int,int> pos;void down(int x,int l,int r){    if (l!=r)    {        tr[x*2].tag+=tr[x].tag;        tr[x*2+1].tag+=tr[x].tag;    }    tr[x].mn+=tr[x].tag;    tr[x].tag=0;}void downdate(int x,int l,int r,int m){    down(x,l,r);    if (l!=r)     {        down(x*2,l,m);        down(x*2+1,m+1,r);    }    if (l!=r)        tr[x].mn=min(tr[x*2].mn,tr[x*2+1].mn);}void make(int x,int l,int r){    tr[x].mn=N;    if (l==r)        return;    int m=(l+r)/2;    make(x*2,l,m);    make(x*2+1,m+1,r);}void change(int x,int l,int r,int i,int j,int val){    int m=(l+r)/2;    if (l==i&&r==j)    {        tr[x].tag+=val;        downdate(x,l,r,m);        return;    }    downdate(x,l,r,m);    if (j<=m)        change(x*2,l,m,i,j,val);    else if (i>m)        change(x*2+1,m+1,r,i,j,val);    else    {        change(x*2,l,m,i,m,val);        change(x*2+1,m+1,r,m+1,j,val);    }    tr[x].mn=min(tr[x*2].mn,tr[x*2+1].mn);}void maintain_mx(int x){    while (t1&&a[x]>a[sta1[t1]])    {        change(1,1,n,sta1[t1],sta1[t1-1]-1,a[x]-a[sta1[t1]]);        sta1[t1--]=0;    }    sta1[++t1]=x;}void maintain_mn(int x){    while (t2&&a[x]<a[sta2[t2]])    {        change(1,1,n,sta2[t2],sta2[t2-1]-1,a[sta2[t2]]-a[x]);        sta2[t2--]=0;    }    sta2[++t2]=x;}int find(int x,int l,int r,int val){    int m=(l+r)/2;    downdate(x,l,r,m);    if (tr[x].mn>val) return 0;    if (l==r) return l;    if (tr[x*2+1].mn<=val)         return find(x*2+1,m+1,r,val);    else return find(x*2,l,m,val);}int main(){    //freopen("t0.in","r",stdin);    scanf("%d %d %d",&n,&K,&d);    fo(i,1,n) scanf("%d",a+i);    R=r=n;    //make(1,1,n);    b[++b[0]]=n;    sta1[0]=n+1;    sta2[0]=n+1;    fd(i,n,1)    {        if (a[i]==a[i+1])            tt++;        else tt=1;        if ((!d)&&tt>=ans)         {            ans=tt;            L=i;        }        if (x=pos[a[i]])            r=min(x-1,r);        pos[a[i]]=i;        maxr[i]=r;        if (d&&((a[i]%d+d)%d!=(a[i-1]%d+d)%d||i==1))         {            b[++b[0]]=i-1;            r=i-1;            mn=mx;            fo(j,i,R)                mn=min(mn,a[j]);            fo(j,i,R)                 a[j]=(a[j]-mn)/d+1;            R=i-1;        }    }    R=n;    if (d)    fo(k,1,b[0])    {        //clear();        fd(i,b[k],b[k+1]+1)        {            // a[i]            if (i==1)             {                i=1;                }            maintain_mx(i);            maintain_mn(i);            if (R>maxr[i])             {                change(1,1,n,maxr[i]+1,R,N);                R=maxr[i];            }            change(1,1,n,i,i,-i);//mx-mn-r            dur=find(1,1,n,K-i);// find the rightermost one which is less than k-l            if (dur-i+1>=ans)            {                ans=dur-i+1;                L=i;            }        }    }    //min max for b[i] l-- r query change add delete    printf("%d %d\n",L,L+ans-1);}
0 0