[HAOI2007] 修筑绿化带
时间限制:1 s 内存限制:128 MB
【问题描述】
为了增添公园的景致,现在需要在公园中修筑一个花坛,同时在画坛四周修建一片绿化带,让花坛被绿化带围起来。
如果把公园看成一个M*N的矩形,那么花坛可以看成一个C*D的矩形,绿化带和花坛一起可以看成一个A*B的矩形。
如果将花园中的每一块土地的“肥沃度”定义为该块土地上每一个小块肥沃度之和,那么,
绿化带的肥沃度=A*B块的肥沃度-C*D块的肥沃度
为了使得绿化带的生长得旺盛,我们希望绿化带的肥沃度最大。
【输入】:
第一行有6个正整数M,N,A,B,C,D
接下来一个M*N的数字矩阵,其中矩阵的第i行j列元素为一个整数Xij,表示该花园的第i行第j列的土地“肥沃度”。
【输出】:
一个正整数,表示绿化带的最大肥沃程度。
【输入输出样例】
parterre.in
4 5 4 4 2 2
20 19 18 17 16
15 14 13 12 11
10 9 8 7 6
5 4 3 2 1
parterre.out
132
【数据范围】
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
单调队列
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 1010
int Map[MAXN][MAXN],N,M,A,B,C,D,S2[MAXN][MAXN]={0};//S2表示C*D矩形的面积
int S[MAXN][MAXN]={0},S1[MAXN][MAXN]={0},Ans=0;//S为前缀和,S1为A*B矩形的面积
class sigal_queue{ //双端队列
private:
int q[MAXN<<1],st,en;
public:
sigal_queue(){
st=1; en=0;
memset(q,0,sizeof(q));
}
inline void clear(){st=1; en=0;}
inline void push_back(int x){q[++en]=x;}
inline int back(){return q[en];}
inline void pop_back(){en--;}
inline void pop_front(){st++;}
inline bool empty(){return st>en;}
inline int front(){return q[st];}
}Q;
inline int max(int x,int y){
if(x>y) return x;
return y;
}
void init(){
scanf("%d%d%d%d%d%d",&M,&N,&A,&B,&C,&D);
for(int i=1;i<=M;i++){
int sum=0;
for(int j=1;j<=N;j++){
scanf("%d",&Map[i][j]);
sum+=Map[i][j];
S[i][j]=sum+S[i-1][j]; //处理出前缀和
}
}
}
void work(){
for(int i=A;i<=M;i++){ //计算两个矩形的面积
for(int j=B;j<=N;j++){
S1[i][j]=S[i][j]-S[i-A][j]-S[i][j-B]+S[i-A][j-B];
}
}
for(int i=C;i<=M;i++){
for(int j=D;j<=N;j++){
S2[i][j]=S[i][j]-S[i-C][j]-S[i][j-D]+S[i-C][j-D];
}
}
}
void solve(){
for(int i=C;i<=M;i++){ //以每一行做单调队列
Q.clear();
for(int j=D;j<=N;j++){
while(!Q.empty()&&S2[i][Q.back()]>=S2[i][j]) Q.pop_back();
Q.push_back(j);
while(Q.front()<=j-B+D+1) Q.pop_front(); //如果超了限制,弹出
if (j>=B-1) S[i][j]=S2[i][Q.front()]; //重新构造前缀,意为最大
}
}
for(int j=B;j<=N;j++){ //以列做单调队列
Q.clear();
for(int i=C;i<=M;i++){
while(!Q.empty()&&S[Q.back()][j-1]>=S[i-1][j-1]) Q.pop_back();
Q.push_back(i-1);
while(Q.front()<=i-A+C) Q.pop_front();
if(i>=A) Ans=max(Ans,S1[i][j]-S[Q.front()][j-1]);
}
}
printf("%d",Ans);
}
int main(){
freopen("parterre.in","r",stdin);
freopen("parterre.out","w",stdout);
init();
work();
solve();
return 0;
}