CF487 B. Strip

Problem - 487B - Codeforces

 

题意:

一个n个数的数组,要求把他们划分为最少的连续段,满足:

1、每段长度至少为l

2、每段的最大值-最小值不超过s

 

dp[i]表示前i个数最少要划分为多少段

枚举j(j<=i-l),若[j+1,i]的最大值-最小值不超过s,那么dp[i]=min(dp[i],dp[j]+1)

枚举j是n^2的,可以二分出满足极值差要求的区间,然后用线段树优化

 

#include<bits/stdc++.h>

using namespace std;

#define N 100003

int mx[N<<2],mi[N<<2],dp[N<<2];
int qm,qi,w;

void build(int k,int l,int r)
{
    dp[k]=2e9;
    if(l==r)
    {
        if(!l) dp[k]=0;
        else
        {
            scanf("%d",&mx[k]);
            mi[k]=mx[k];
        }
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    mx[k]=max(mx[k<<1],mx[k<<1|1]);
    mi[k]=min(mi[k<<1],mi[k<<1|1]);
    dp[k]=min(dp[k<<1],dp[k<<1|1]);
}

void query(int k,int l,int r,int opl,int opr)
{
    if(l>=opl && r<=opr)
    {
        qm=max(qm,mx[k]);
        qi=min(qi,mi[k]);
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) query(k<<1,l,mid,opl,opr);
    if(opr>mid) query(k<<1|1,mid+1,r,opl,opr);
}

void change(int k,int l,int r,int pos,int x)
{
    if(l==r)
    {
        dp[k]=x;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid) change(k<<1,l,mid,pos,x);
    else change(k<<1|1,mid+1,r,pos,x);
    dp[k]=min(dp[k<<1],dp[k<<1|1]);
}

void query2(int k,int l,int r,int opl,int opr)
{
    if(l>=opl && r<=opr)
    {
        w=min(w,dp[k]);
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) query2(k<<1,l,mid,opl,opr);
    if(opr>mid) query2(k<<1|1,mid+1,r,opl,opr);
}

int main()
{
    int n,s,l;
    scanf("%d%d%d",&n,&s,&l);
    build(1,0,n);
    int L,R,mid,tmp;
    for(int i=l;i<=n;++i)
    {
        L=1;
        R=i-l+1;
        tmp=-1;
        while(L<=R)
        {
            mid=L+R>>1;
            qm=-2e9;
            qi=2e9;
            query(1,0,n,mid,i);
            if(qm-qi<=s) 
            {
                tmp=mid;
                R=mid-1;
            }
            else L=mid+1;
        }
        if(tmp!=-1)
        {
            w=2e9;
            if(tmp-1<=i-l) query2(1,0,n,tmp-1,i-l);
            if(w!=2e9) change(1,0,n,i,w+1);
        }
    }
    w=2e9;
    query2(1,0,n,n,n);
    if(w==2e9) w=-1;
    printf("%d",w);
}

 

上一篇:剑指 Offer 42. 连续子数组的最大和


下一篇:Linux