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

题面

题解

题目意思比较简单, 就不在这里赘述了

本着练习平衡树的思路, 我把方法尝试往上面去套, 结果想不出

只能弃掉平衡树

最后想出来的方法是这样的

我们运用类似于高维前缀和那样一维一维加上去的方法

先横着统计在某个范围内和最小的 \(c * d\) 矩阵, 把贡献算在范围的右下角

注意, 这里保证了这个矩阵在以 \((i, j)\) 为右下角的某个范围之内

然后再竖着计算答案, 我们固定 \(a * b\) 矩形的右边在某一列, 就只用考虑行的变化了

从上往下依次枚举右下角, 每次弹出不合法的, 然后跟合法的和的 \(max\) 做差取最大值

因为右下角储存的是一段以它为右下端点, 长度为 \(b\) , 高度为 \(c\) , 的范围内和最小的 \(c * d\) 矩阵

所以只要定了列, 它就不会超过列的影响范围, 也就是说, 列上面不会有冲突

所以只用看行之间的影响即可

这两步可以用单调队列实现

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int N = 1005;
using namespace std;

int n, m, a, b, c, d, w[N][N], sum[N][N], val[N][N], l, r, ans;
struct node { int id, val; } q[N]; 

template < typename T >
inline T read()
{
    T x = 0, w = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * w;
}

int getsum(int x1, int y1, int x2, int y2)
{
    return sum[x1][y1] - sum[x1][y2] - sum[x2][y1] + sum[x2][y2];
}

int main()
{
    n = read <int> (), m = read <int> (), a = read <int> (), b = read <int> (), c = read <int> (), d = read <int> ();
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            w[i][j] = sum[i][j] = read <int> ();
            sum[i][j] = sum[i][j] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
        }
    memset(val, 0x3f, sizeof(val));
    for(int tmp, i = c; i <= n; i++)
    {
        l = 1, r = 0;
        for(int j = d; j <= n; j++)
        {
            tmp = getsum(i, j, i - c, j - d);
            while(l <= r && q[r].val >= tmp)
                r--;
            q[++r].val = tmp, q[r].id = j - d + 1;
            while(l <= r && q[l].id <= j - b + 2)
                l++;
            val[i][j] = q[l].val;
        }
    }
    for(int tmp, j = b - 1; j < m; j++)
    {
        l = 1, r = 0;
        for(int i = c; i <= n; i++)
        {
            if(i - c + a - 1 <= n)
            {
                tmp = getsum(i - c + a - 1, j + 1, i - c - 1, j - b + 1);
                while(l <= r && q[r].val <= tmp)
                    r--;
                q[++r].val = tmp, q[r].id = i - c + a - 1;
            }
            while(l <= r && q[l].id <= i || q[l].id - a + 1 >= i - c + 1)
                l++;
            ans = max(ans, q[l].val - val[i][j]);
        }
    }
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/ztlztl/p/12194389.html

时间: 2024-10-31 18:51:50

[题解] [HAOI2007] 修筑绿化带的相关文章

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

洛谷.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的和,n

修筑绿化带题解

修筑绿化带题解 我的做法实际上神奇且麻烦,大家其实可以看一下别人的做法. 这是一个单调队列优化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最小值(实际上就是每个

单调队列单调栈

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

贪心(qwq)习题题解

贪心(qwq)习题题解 SCOI 题解 [ SCOI2016 美味 ] 假设已经确定了前i位,那么答案ans一定属于一个区间. 从高位往低位贪心,每次区间查找是否存在使此位答案为1的值. 比如6位数确定了前三位\((101...)_2\),下一位应该是1 那么\(a_i+x_i\)的查找区间为:\([(101100)_2,(101111)_2]\) ,同理如果应该是0则为\([(101000)_2,(101011)_2]\). 注意到有区间\([l,r]\)范围的限制所以用主席树维护即可. [

题解 P1463 【[POI2002][HAOI2007]反素数】

题目链接 Solution [POI2002][HAOI2007]反素数 题目大意:设\(x\)的约数个数为\(g(x)\),若对于所有\(i \in [1,x)\),都有\(g(i) < g(x)\),则称\(x\)为反素数,求不超过\(n\)的最大反素数 分析:这道题可以打表,但是打表也要讲求方法 对于\(n = 2 \times 10^9\)这种级别的数据,如果你用\(O(n^2)\)算法,估计你得搬出太湖之光才能以可以接受的速度跑完(而且你还得考虑并行计算效率问题) 我们把这个问题分成两

【题解】覆盖问题 BZOJ1052 HAOI2007

题目描述 某人在山上种了N棵小树苗.冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄膜把这些小树遮盖起来,经过一番长久的思考,他决定用3个LL的正方形塑料薄膜将小树遮起来.我们不妨将山建立一个平面直角坐标系,设第i棵小树的坐标为(Xi,Yi),3个LL的正方形的边要求平行与坐标轴,一个点如果在正方形的边界上,也算作被覆盖.当然,我们希望塑料薄膜面积越小越好,即求L最小值. 输入输出 input第一行有一个正整数N,表示有多少棵树.接下来有N行,第i+1行有2个整数Xi,Yi

【题解】覆盖问题 BZOJ1052 HAOI2007 二分

题目描述 某 人在山上种了N棵小树苗.冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄膜把这些小树遮盖起来,经过一番长久的思考,他决定用 3个LL的正方形塑料薄膜将小树遮起来.我们不妨将山建立一个平面直角坐标系,设第i棵小树的坐标为(Xi,Yi),3个LL的正方形的边要求平行与坐标 轴,一个点如果在正方形的边界上,也算作被覆盖.当然,我们希望塑料薄膜面积越小越好,即求L最小值. 输入输出 input第一行有一个正整数N,表示有多少棵树.接下来有N行,第i+1行有2个整数Xi