• CF487B Strip


    Solution

    状态 (dp_i) 表示把前 (i) 个数可以划分成的最小段数。那么对于转移,就可以枚举一个 (j) 表示将 ((j,i]) 划成一段,那么就有 (dp_{i}=min{dp_j}+1).

    这道题的关键在于如何维护出 (j) 的取值范围。首先 (j) 肯定必须小于等于 (i-l) ,因为每段长度不小于 (l)。其次,容易发现当 (i) 是固定的时候,(j) 的取值越小那么当前段的最值之差就越大(至少是不降的)。所以可以用单调队列维护出最值之差恰好不大于 (s) 的位置——这个过程可以用两个单调队列分别维护一下最大值和最小值。

    那么现在我们就已经能知道决策区间的左右端点了,又发现这个区间的移动是单调的,即左右端点不减。那么这个 (dp) 的最小值也可以用单调队列维护。

    复杂度 (O(n))

    #include<stdio.h>
    #define N 100007
     
    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;
    }
     
    /* q1 max q2 min */
     
    int n,l,s,dp[N];
    int pos=1,a[N],q1[N],q2[N],q3[N];
    int h1=1,h2=1,h3=1,t1=0,t2=0,t3=0;
     
    int main(){
        n=read(),s=read(),l=read();
        for(int i=1;i<=n;i++){
            a[i]=read();
            while(h1<=t1&&a[q1[t1]]<=a[i]) t1--;
            while(h2<=t2&&a[q2[t2]]>=a[i]) t2--;
            q1[++t1]=q2[++t2]=i;
            if(i-l>=0){
                while(h3<=t3&&dp[i-l]<=dp[q3[t3]]) t3--;
                q3[++t3]=i-l;
            }
            while(pos<=i-l+1&&a[q1[h1]]-a[q2[h2]]>s){
                if(h1<=t1&&q1[h1]<(++pos)) h1++;
                if(h2<=t2&&q2[h2]<pos) h2++;
                if(h3<=t3&&q3[h3]<pos-1) h3++;
            }
            if(h3<=t3){
                if(dp[q3[h3]]==n+1) dp[i]=n+1;
                else dp[i]=dp[q3[h3]]+1;
            }else dp[i]=n+1;
        }
        printf("%d",(dp[n]!=n+1)? dp[n]:-1);
    }
    
  • 相关阅读:
    【JDK1.8】JDK1.8集合源码阅读——LinkedList
    【JDK1.8】JDK1.8集合源码阅读——ArrayList
    【JDK1.8】JDK1.8集合源码阅读——IdentityHashMap
    【Spring】Spring boot多数据源历险记
    【JDK1.8】JDK1.8集合源码阅读——LinkedHashMap
    还未完成的任务
    做题中的错误总结
    cdq分治学习笔记
    计算几何复习笔记
    线性基学习笔记
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14193199.html
Copyright © 2020-2023  润新知