洛谷.2219.[HAOI2007]修筑绿化带(单调队列)

题目链接 洛谷
COGS.24

对于大的矩阵可以枚举;对于小的矩阵,需要在满足条件的区域求一个矩形和的最小值
预处理S2[i][j]表示以(i,j)为右下角的C\(*\)D的矩阵和,
然后对于求矩形区域的最小值,可以先将每行看做一个数列,对于每个点y,得到一个[y-(B-3),y]的最小值
处理完行后得到Minr[][],对每列的进行同样的操作,就可以得到Min[x][y]表示([x-A+3,x],[y-B+3,y])的最小矩形和
但是注意单调队列处理的是S2,S2表示的是C\(*\)D的和,not a single point!所以端点应该是([x-A+C+1],[y-B+D+1])

原先做过这样的套路题,还是费了近一下午==不行效率太低了

#include <cstdio>
#include <cctype>
//#define gc() getchar()
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1005,MAXIN=6e5;

int n,m,A,B,C,D,S[N][N],S1[N][N],S2[N][N],q[N],Minr[N][N];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
//void Debug(int a[N][N],int s,int s2)
//{
//  puts("Debug");
//  for(int i=s; i<=n; ++i,putchar('\n'))
//      for(int j=s2; j<=m; ++j) printf("%d ",a[i][j]);
//  putchar('\n');
//}
void Pre()
{
    for(int i=C+1; i<n; ++i)//第1~C,n行用不到
    {
        int h=1,t=0;
        for(int j=D+1; j<m; ++j)
        {
            while(h<=t && S2[i][q[t]]>=S2[i][j]) --t;
            q[++t]=j;
            if(q[h]<=j-B+D+1) ++h;
            Minr[i][j]=S2[i][q[h]];
        }
    }
//  Debug(S,1,1);
//  Debug(S1,A,B);
//  Debug(S2,C,D);
//  Debug(Minr,2,2);
}
void Solve()
{
    int res=0;
    for(int j=D+1; j<m; ++j)//枚举小矩形可放范围,行+1列+1即大矩形的位置
    {
        int h=1,t=0;
        for(int i=C+1; i<n; ++i)
        {
            while(h<=t && Minr[q[t]][j]>=Minr[i][j]) --t;
            q[++t]=i;
            if(q[h]<=i-A+C+1) ++h;
            if(res<S1[i+1][j+1]-Minr[q[h]][j]) res=S1[i+1][j+1]-Minr[q[h]][j];
        }
    }
    printf("%d",res);
}

int main()
{
    n=read(),m=read(),A=read(),B=read(),C=read(),D=read();
    if(n<=2||m<=2) {putchar('0'); return 0;}
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=m; ++j)
            S[i][j]=read()+S[i][j-1]+S[i-1][j]-S[i-1][j-1];
    for(int i=A; i<=n; ++i)
        for(int j=B; j<=m; ++j)
            S1[i][j]=S[i][j]-S[i][j-B]-S[i-A][j]+S[i-A][j-B];
    for(int i=C+1; i<=n; ++i)
        for(int j=D+1; j<=m; ++j)
            S2[i][j]=S[i][j]-S[i][j-D]-S[i-C][j]+S[i-C][j-D];
    Pre(), Solve();

    return 0;
}

原文地址:https://www.cnblogs.com/SovietPower/p/8470244.html

时间: 2024-10-04 13:22:00

洛谷.2219.[HAOI2007]修筑绿化带(单调队列)的相关文章

洛谷P1725 琪露诺 单调队列优化 DP

洛谷P1725 琪露诺 单调队列优化 DP 题意:1--n 每个点都有一个权值,从当前点i可以到达i+l--i+r 之间的点, 动态规划 方程 为 f[ i ] = max(f[ i ],f[ k ] ) +a[ i ] i-r<=k<=i-l 然而这样复杂度 就为 n^2 因为相当于 dp 是在求 一段区间的最大值,而这个最大值就可以用O(n) 来维护 注意 这个O(n) 是均摊O(n) 即将所有固定区间长度的 最大值求出来 是 O(n)的这样就把复杂度降到 O(n) 级别了 1 #incl

洛谷P1823 音乐会的等待 单调栈

洛谷P1823 音乐会的等待 单调栈 维护一个上升的单调栈 用以记录有当前这个数向后能看到几个数 但是每次加入一个数 时 他能看到的 是 单调栈中所有比他小的 和跟他一样的数 比他小的下次就没有用了,所以直接退栈 但是 相同的数到后面还是可能会有贡献的,所以贡献算完以后又要进栈 最后如果栈中还有元素,那么栈顶一定能看到自身,所以+1 1 #include <bits/stdc++.h> 2 #define For(i,j,k) for(int i=j;i<=k;i++) 3 #defin

P2219 [HAOI2007]修筑绿化带

题目描述 为了增添公园的景致,现在需要在公园中修筑一个花坛,同时在画坛四周修建一片绿化带,让花坛被绿化带围起来. 如果把公园看成一个M * N的矩形,那么花坛可以看成一个C * D的矩形,绿化带和花坛一起可以看成一个A * B的矩形. 如果将花园中的每一块土地的"肥沃度"定义为该块土地上每一个小块肥沃度之和,那么, 绿化带的肥沃度=A * B块的肥沃度-C * D块的肥沃度 为了使得绿化带的生长得旺盛,我们希望绿化带的肥沃度最大. 输入输出格式 输入格式: 第一行有6个正整数M,N,A

[HAOI2007] 修筑绿化带

类型:单调队列 传送门:>Here< 题意:给出一个$M*N$的矩阵,每一个代表这一格土地的肥沃程度.现在要求修建一个$C*D$的矩形花坛,矩形绿化带的面积为$A*B$,要求花坛被包裹在绿化带中,且不能碰到绿化带边缘.问绿化带的最大肥沃程度 解题思路 暴力做法:枚举绿化带,然后选出能使其肥沃程度最大的花坛位置. 很容易发现要使绿化带的肥沃程度最大,也就是让所选的花坛的肥沃程度尽量小.由此,问题转化为了求固定矩形内部规定大小的最小子矩形 为了表达方便,以下称绿化带为矩形$AB$,花坛为矩形$CD

洛谷P2216 [HAOI2007] 理想的正方形

题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表示a,b,n的值 第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔. 输出格式: 仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值. 输入输出样例 输入样例#1: 5 4 2 1 2 5 6 0 17 16 0 16 17 2 1 2 10 2

[题解] [HAOI2007] 修筑绿化带

题面 题解 题目意思比较简单, 就不在这里赘述了 本着练习平衡树的思路, 我把方法尝试往上面去套, 结果想不出 只能弃掉平衡树 最后想出来的方法是这样的 我们运用类似于高维前缀和那样一维一维加上去的方法 先横着统计在某个范围内和最小的 \(c * d\) 矩阵, 把贡献算在范围的右下角 注意, 这里保证了这个矩阵在以 \((i, j)\) 为右下角的某个范围之内 然后再竖着计算答案, 我们固定 \(a * b\) 矩形的右边在某一列, 就只用考虑行的变化了 从上往下依次枚举右下角, 每次弹出不合

[POI 2008&amp;洛谷P3467]PLA-Postering题解(单调栈)

Description Byteburg市东边的建筑都是以旧结构形式建造的:建筑互相紧挨着,之间没有空间.它们共同形成了一条长长的,从东向西延伸的建筑物链(建筑物的高度不一). Byteburg市的市长Byteasar,决定将这个建筑物链的一侧用海报覆盖住.并且想用最少的海报数量,海报是矩形的. 海报与海报之间不能重叠,但是可以相互挨着(即它们具有公共边),每一个海报都必须贴近墙并且建筑物链的整个一侧必须被覆盖(意思是:海报需要将一侧全部覆盖,并且不能超出建筑物链) 输入格式:第一行为一个整数n

单调队列单调栈

单调队列单调栈 Tags:数据结构 更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1041449 一.概述 单调队列单调栈是很基础的数据结构,常用来优化一些东西比如说优化DP 那么大概意思就是在栈或队列中按照某关键字单调维护信息,从而实现一些功能 其实很久之前接触过单调队列和单调栈,但一直没有刷题,趁这两天被LCT弄晕的时候复习下这些 先看题 二.题单 普及- [x] P1886 滑动窗口 https://www.luogu.org/problemnew/

洛谷 U4792 Acheing 单调队列

/*洛谷 U4792 Acheing 二维线段树 n*n*logn*logn T成傻逼2333 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 1010 #define lc k*2 #define rc k*2+1 #define mid (l+r)/2 using namespace std; int n,m,k,g[maxn][maxn],x,y,z; int x1,x2,