机房测试7:paint(分治+st表)

题目:

 

 

 

 分析:

与noip2018 T1十分相似,那道题可以看做这道题只能横着涂,具体思路是:

第一次先选取最小的高度minn,让所有高度都减去minn,1~n的连续段就被分成了许多块,对于每一个块重复上述过程,直到所有的柱子都为0。

这种过程类似于递归处理块,可以用dfs解决。

对于区间l~r,在这道题中,我们可以横着选,也可以花费r-l+1,选择竖着选,只需要在递归的时候比较一下答案即可。

但每次找最小值及其位置的时候,用st表维护最小值及其位置,可以将n^2化为n*logn

#include<bits/stdc++.h>
using namespace std;
#define ri register int
#define ll long long
#define N 500005
int n,low[N],a[N];
ll read()
{
    ll x=0,fl=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') fl=-1; ch=getchar(); }
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
    return x*fl;
}
struct st { 
    int w; int pos;//开long long会爆空间 
    inline bool friend operator<(const st x,const st y){
        return x.w<y.w;
    }
}mn[N][22];
st calc(int l,int r)
{
    int k=low[r-l+1];
    return min(mn[l][k],mn[r-(1<<k)+1][k]);
}
ll dfs(int l,int r,int h)
{
    if(l>r || r<0) return 0;
    //if(l==r) return 1;
    st minn=calc(l,r);
    ll ans=minn.w-h;
    ans+=dfs(l,minn.pos-1,minn.w);//递归处理块 
    ans+=dfs(minn.pos+1,r,minn.w);
    return min((ll)r-l+1,ans);//考虑竖着涂会不会更优 
}
int main()
{
    freopen("paint.in","r",stdin);
    freopen("paint.out","w",stdout);
    n=read();
    for(ri i=1;i<=n;++i) a[i]=read();
    low[0]=-1;
    for(ri i=1;i<=n;++i) low[i]=low[i/2]+1;
    for(ri i=1;i<=n;++i) mn[i][0].w=a[i],mn[i][0].pos=i;
    for(ri j=1;j<=20;++j)
     for(ri i=1;i+(1<<j)-1<=n;++i)
      mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
    printf("%lld\n",dfs(1,n,0));
}
/*
5
2 2 1 2 1
*/
View Code

 

转载于:https://www.cnblogs.com/mowanying/p/11632445.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值