题目描述
为了增添公园的景致,现在需要在公园中修筑一个花坛,同时在画坛四周修建一片绿化带,让花坛被绿化带围起来。
如果把公园看成一个M*N的矩形,那么花坛可以看成一个C*D的矩形,绿化带和花坛一起可以看成一个A*B的矩形。
如果将花园中的每一块土地的“肥沃度”定义为该块土地上每一个小块肥沃度之和,那么,
绿化带的肥沃度=A*B块的肥沃度-C*D块的肥沃度
为了使得绿化带的生长得旺盛,我们希望绿化带的肥沃度最大。
输入输出格式
输入格式:
第一行有6个正整数M,N,A,B,C,D
接下来一个M*N的数字矩阵,其中矩阵的第i行j列元素为一个整数Xij,表示该花园的第i行第j列的土地“肥沃度”。
输出格式:
一个正整数,表示绿化带的最大肥沃程度。
输入输出样例
说明
数据范围
30%的数据,1<=M,N<=50
100%的数据,1<=M,N<=1000,1<=A<=M,1<=B<=N,1<=C<=A-2,1<=D<=B-2,1<=“肥沃度”<=100
容易发现其实就是对每一个可以放置a*b矩形的位置求出内部一个权值最小矩形。
二维最值显然可以树套树,但是这里不需要,没有修改操作并且每次查询的矩形大小一直相等,容易想到单调队列。
那么我们用单调队列套单调队列。先把所有c*d大小矩形的内部和归到左上角。底层用n个单调队列移着走,并且更新行上固定宽度的最小值。每移到新的一列统计答案,发现也是求固定长度区间最小值,再用一个单调队列移出答案就行了。
边界有点恶心,一定看清楚再写。
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn = 1e3 + 5;
int mp[maxn][maxn], n, m, a, b, c, d, ans;
int sum[maxn][maxn], h, w, nowc, mn[maxn];
typedef pair<int, int > pii;
deque<pii > q[maxn], nq;
int GetSum(int x1, int y1, int x2, int y2) {
return sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1];
}
void push(deque<pii > & q, int pos, int x, int l) {
while(!q.empty() && q.front().second <= pos - l)
q.pop_front();
while(!q.empty() && q.back().first > x)
q.pop_back();
q.push_back(make_pair(x, pos));
}
void Move(int col) {
for(register int i = 1; i <= n - c + 1; ++i) {
push(q[i], col, mp[i][col], w - 1), mn[i] = q[i].front().first;
//putchar('*');
}
//putchar('\n');
}
int main() {
scanf("%d%d%d%d%d%d", &n, &m, &a, &b, &c, &d);
for(register int i = 1; i <= n; ++i)
for(register int j = 1; j <= m; ++j)
scanf("%d", &mp[i][j]), sum[i][j] += mp[i][j];
for(register int i = 1; i <= n; ++i)
for(register int j = 1; j <= m; ++j)
sum[i][j] += sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1];
memset(mp, 0, sizeof(mp));
for(register int i = 1; i <= n - c + 1; ++i)
for(register int j = 1; j <= m - d + 1; ++j)
mp[i][j] = GetSum(i, j, i + c - 1, j + d - 1);
h = a - c, w = b - d;
int tp = 0, tp2 = 0;
for(register int i = 1; i <= m - b + 1; ++i) {
while(tp < i + w - 1) Move(++tp);
nq.clear(), tp2 = 0;
for(register int j = 1; j <= n - a + 1; ++j) {
while(tp2 < j + h - 1)
++tp2, push(nq, tp2, mn[tp2], h - 1);
ans = max(GetSum(j, i, j + a - 1, i + b - 1) - nq.front().first, ans);
}
}
printf("%d", ans);
return 0;
}
rockdu
没有帐号? 立即注册