修筑绿化带题解

修筑绿化带题解

我的做法实际上神奇且麻烦,大家其实可以看一下别人的做法。

这是一个单调队列优化DP题(废话)。

我的大概做法是:将每个c乘d的矩形化成一个点,将从a乘b的矩形中选一个c乘d的矩形转化为:在(a-c+1)*(b-d+1)的矩形中选一个值最小的点。

具体做法如下:

1.求出二维前缀和p,再求出以一个点为左上角的c乘d的矩形的值之和a。

2.求出每一以某点开始的长度为a-c+1的列的最小值sum。

3.剩下的就是在n-a+1行上,每一行求出长度为b-d+1的sum最小值(实际上就是每个a乘b的矩形中c乘d矩形的最小值),ans跟a乘b矩形权值和-最小值取max即可。

具体看代码吧:

#include<bits/stdc++.h>
using namespace std;
const int N=1006;
int n,m,t1,t2,t3,t4,t,head=1,tail=0,p[N][N],a[N][N],sum[N][N],q[N],ans=-1;
inline int read(){
   int T=0,F=1; char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
   while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar(); 
   return F*T; 
}
int main(){
    n=read(),m=read(),t1=read(),t2=read(),t3=read(),t4=read();
    for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) p[i][j]=read(),p[i][j]=p[i-1][j]+p[i][j-1]-p[i-1][j-1]+p[i][j];
    for(int i=1;i<=n-t3+1;++i) for(int j=1;j<=m-t4+1;++j) a[i][j]=p[i+t3-1][j+t4-1]-p[i+t3-1][j-1]+p[i-1][j-1]-p[i-1][j+t4-1];
    for(int i=1;i<=m-t4+1;++i){
        tail=0,head=1;
        for(int j=2;j<=t1-t3;++j){
            while(tail&&a[q[tail]][i]>=a[j][i]) --tail;
            q[++tail]=j;
        }
        for(int j=1;j<=n-t1+1;++j){ 
            sum[j][i]=a[q[head]][i];
            while(q[head]<=j+1&&head<=tail) ++head;
            while(tail>=head&&a[q[tail]][i]>=a[j+t1-t3][i]) --tail;
            q[++tail]=j+t1-t3;
        } 
    }
    for(int i=1;i<=n-t1+1;++i){
        head=1,tail=0;
        for(int j=2;j<=t2-t4;++j){
            while(tail&&sum[i][q[tail]]>=sum[i][j]) --tail;
            q[++tail]=j;
        }
        for(int j=1;j<=m-t2+1;++j){ 
            ans=max(ans,p[i-1][j-1]-p[i-1][j+t2-1]+p[i+t1-1][j+t2-1]-p[i+t1-1][j-1]-sum[i][q[head]]);
            while(q[head]<=j+1&&head<=tail) ++head;
            while(tail>=head&&sum[i][q[tail]]>=sum[i][j+t2-t4]) --tail;
            q[++tail]=j+t2-t4;
        } 
    }
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/ljk123-de-bo-ke/p/11478448.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值