zoukankan      html  css  js  c++  java
  • YYH的苍天大竹(NOIP模拟赛Round 6)

    题目描述

    YYH擅长种竹子。今天他收获了一根竹子,准备将这根柱子卖给CHS。这个竹子有n-1个竹节。CHS要求一定要从竹节的地方砍,而且砍成若干段后每一段竹子中最长的一小段竹子和最短的一小段的长度差不能超过s,一段竹子至少含有l小段竹子。这可让YYH郁闷了,他希望留点力气刷题,所以他想知道他最少可以将整根竹子砍成多少段。

    输入输出格式

    输入格式:

    输入第一行三个整数,n,s,l,意义如题目所描述

    输入第二行n个整数,a[1],a[2],……,a[n],分别为每小段竹子的长度

    输出格式:

    如果有满足条件的砍法,输出整根竹子砍成最少的段数。否则输出-1

    这道题我们很显然要用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
    ",f[n+m]>=inf?-1:f[n+m]);
        return 0;
    }
  • 相关阅读:
    dev、test和prod是什么意思?
    构建项目时依赖库下载不下来的解决
    自定义view规范步骤步骤
    【转】MIUI8以及ViVO X9上在Android Studio运行出错集及其解决方案
    Ubuntu 16.04使用git
    Android中WebView与H5的交互,Native与JS方法互调
    [转] Fragment——startActivityForResult后onActivityResult无反应之问题总结
    解决运行github项目build时间长问题
    SVN回滚至某个版本
    【算法】种花问题
  • 原文地址:https://www.cnblogs.com/ghostfly233/p/6930075.html
Copyright © 2011-2022 走看看