题目:修筑绿化带,这中间的j-b+d+1,和i-a+c+1,始终没弄明白是怎么回事。
[HAOI2007] 修筑绿化带
【问题描述】
为了增添公园的景致,现在需要在公园中修筑一个花坛,同时在画坛四周修建一片绿化带,让花坛被绿化带围起来。
如果把公园看成一个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"debug.h"
const int N=1010;
int n,m,a,b,c,d,i,j,ans,s[N][N],v[N][N],dp[N][N],DP[N][N];
int q[N],head,tail;
int main()
{
freopen("parterre.in","r",stdin);
freopen("parterre.out","w",stdout);
scanf("%d%d%d%d%d%d",&n,&m,&a,&b,&c,&d);
//计算总和
for (i=1;i<=n;i++)
for (j=1;j<=m;j++){
scanf("%d",&s[i][j]);
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
//在m*n中c*d对应的总和值
for (i=2;i<=n-c;i++)
for (j=2;j<=m-d;j++)
v[i][j]=s[i+c-1][j+d-1]-s[i+c-1][j-1]-s[i-1][j+d-1]+s[i-1][j-1];
//for (i=2;i<=n-c;i++) print(v[i],2,m-d,' ');writeln;
for (i=2;i<=n-c;i++){
head=1,tail=0;
for (j=2;j<=m-d;j++){
while (head<=tail&&q[head]<=j-b+d+1) head++;
//上面的j-b+d+1,没弄明白什么回事,同理下面的i-a+c+1.
while (head<=tail&&v[i][q[tail]]>v[i][j]) tail--;
q[++tail]=j;
dp[i][j]=v[i][q[head]];
}
}
//for (i=2;i<=n-c;i++) print(dp[i],2,m-d,' ');writeln;
for (j=2;j<=m-d;j++){
head=1;tail=0;
for (i=2;i<=n-c;i++){
while (head<=tail&&q[head]<=i-a+c+1) head++;
while (head<=tail&&dp[q[tail]][j]>dp[i][j]) tail--;
q[++tail]=i;
DP[i][j]=dp[q[head]][j];
}
}
//for (i=2;i<=n-c;i++) print(DP[i],2,m-d,' ');writeln;
for (i=1;i<=n-a+1;i++)
for (j=1;j<=m-b+1;j++){
int sum=s[i+a-1][j+b-1]-s[i+a-1][j-1]-s[i-1][j+b-1]+s[i-1][j-1];
sum-=DP[i+a-c-1][j+b-d-1];
if (sum>ans) ans=sum;
}
printf("%d\n",ans);
return 0;
}
#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;
}