zoukankan      html  css  js  c++  java
  • CF407E k-d-sequence

    Description

    给定序列 ({a_n}),求最长的区间,使得至多添加 (k) 个数后,重新排序后是一个公差为 (d) 的等差数列。

    Solution

    先特判掉 (d=0) 的情况,添数是无用的,只需要求最长的相同的段即可。

    (d eq 0) ,由于是等差数列,所以(mod d) 的值应该相同,先预处理出膜 (d) 值相同的一段,然后提出来单独考虑。

    一段区间合法当且仅当值域连续,无重复,并且至的个数小于等于区间长度加 (k)

    无重复只需要移动左端点,后面的限制可以列成

    [max-min+1leq (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);
        }
    }
    
  • 相关阅读:
    hdu 3333 树状数组+离线处理
    poj 2352 树状数组 OR Treap
    hdu 1698 线段树
    【概率dp】D. Card Collector
    【分段哈希】H. Paint the Wall
    【置换】G. Poker 2.0
    【概率dp】C. Race to 1 Again
    【dp】D. Caesar's Legions
    【并查集】F.find the most comfortable road
    【算法系列学习】连续邮资问题
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15158580.html
Copyright © 2011-2022 走看看