首页 > 代码库 > YYH的苍天大竹(NOIP模拟赛Round 6)

YYH的苍天大竹(NOIP模拟赛Round 6)

原题传送门

这道题我们很显然要用DP来做。

那么首先我们需要构造出一个DP方程

f[i]肯定由另一个状态dp转移后+1得到,那么这个状态是什么呢?

很明显就是mint[i]~i-k(在此mint表示的是以i为结尾的竹子最左端最多能延展到的位置)

看到这个之后我们想到了一个N^2DP

但是还是不够

我们想一想如何得到mint?

mint就是判断一段区间的最大值减去最小值是否满足题意

那么我们可不可以用数据结构得出这个答案呢?

显然我们可以用线段树来优化这个过程

时间复杂度O(nlogn)

同样在得出答案的过程我们也可以用线段树加速

下面贴代码

#include<cstdio>
#include<cstring>
#define inf 0x3f3f3f3f
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
using namespace std;
int a[100005];
struct mm{
    int v1,v2;
}t[300005];
int mint[100005];
int f[300005];
int m=1,n,s,l;
void pushdown(int i){t[i].v1=min(t[i<<1].v1,t[i<<1|1].v1);t[i].v2=max(t[i<<1].v2,t[i<<1|1].v2);}
void buildtree(){
    while(m<n+2)m<<=1;
    for(int i=1;i<=n;i++)
    t[i+m].v1=t[i+m].v2=a[i];
    for(int i=m-1;i;i--)
    pushdown(i); 
}
int query(int l,int r)
{
    int maxn=-inf,minn=inf;
    for(l=l+m-1,r=r+m+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1)minn=min(minn,t[l^1].v1),maxn=max(maxn,t[l^1].v2);
        if(r&1)minn=min(minn,t[r^1].v1),maxn=max(maxn,t[r^1].v2);
    }
    return maxn-minn;
}
int que(int l,int r)
{
    int minn=inf;
    for(l+=m-1,r+=m+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1)minn=min(minn,f[l^1]);
        if(r&1)minn=min(minn,f[r^1]);
    }
    return minn;
}
void push(int x){f[x]=min(f[x<<1],f[x<<1|1]);}
void add(int x,int y){for(f[x+=m]=y,x>>=1;x;x>>=1)push(x);}
int main(){
    memset(f,127/3,sizeof(f));
    scanf("%d%d%d",&n,&s,&l);n++;
    for(int i=2;i<=n;i++)scanf("%d",&a[i]);
    a[1]=a[2];
    buildtree();
    int le=1;
    for(int i=1;i<=n;i++)
    {
        int tmp=query(le,i);
        while(tmp>s)
        {
            tmp=query(++le,i);
        }
        mint[i]=le;
    }
    add(1,0);
    for(int i=2;i<=n;i++)
        if(max(1,mint[i]-1)>i-l)add(i,inf);
        else add(i,que(max(1,mint[i]-1),i-l)+1);
    printf("%d\n",f[n+m]>=inf?-1:f[n+m]);
    return 0;
}

 

YYH的苍天大竹(NOIP模拟赛Round 6)