洛谷P2216 [HAOI2007]理想的正方形
Time Limit: 10 Sec
Memory Limit: 162 MB
Description
有一个ab的整数组成的矩阵,现请你从中找出一个nn的正方形区域,使得该区域所有数中的最大值和最小值
的差最小。
Input
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每
行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000
Output
仅一个整数,为ab矩阵中所有“nn正方形区域中的最大整数和最小整数的差值”的最小值。
题目分析
用
m
x
[
i
]
[
j
]
,
m
i
[
i
]
[
j
]
mx[i][j],mi[i][j]
mx[i][j],mi[i][j]分别保存矩阵中第i行第j-n+1列到第j列的最大值与最小值
这两个数组可以用一次单调队列预处理出
然后对于每一列j
我们分别求出
m
a
x
(
m
x
[
i
−
n
+
1
]
[
j
]
—
m
x
[
i
]
[
j
]
)
max(mx[i-n+1][j]—mx[i][j])
max(mx[i−n+1][j]—mx[i][j]) 与
m
i
n
(
m
i
[
i
−
n
+
1
]
[
j
]
—
m
i
[
i
]
[
j
]
)
(
n
<
=
i
<
=
a
)
min(mi[i-n+1][j]—mi[i][j])(n<=i<=a)
min(mi[i−n+1][j]—mi[i][j])(n<=i<=a)
这样就相当于得到了矩阵
(
i
−
n
+
1
,
j
−
n
+
1
)
,
(
i
,
j
)
(i-n+1,j-n+1),(i,j)
(i−n+1,j−n+1),(i,j)中的最大值与最小值
代码有点乱=_=
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=1010;
int a,b,n;
int d[maxn][maxn];
int q[2][maxn],ll[2],rr[2];
int mx[maxn][maxn],mi[maxn][maxn];
int ans=1e9;
int main()
{
a=read(); b=read(); n=read();
for(int i=1;i<=a;++i)
for(int j=1;j<=b;++j)
d[i][j]=read();
for(int j=1;j<=a;++j)
{
ll[0]=ll[1]=rr[0]=rr[1]=1;
q[0][1]=q[1][1]=0;
for(int i=1;i<=b;++i)
{
while(ll[0]<rr[0]&&q[0][ll[0]]<i-n+1)++ll[0];
while(ll[0]<rr[0]&&d[j][q[0][rr[0]-1]]>=d[j][i])--rr[0];
q[0][rr[0]++]=i;
mi[j][i]=d[j][q[0][ll[0]]];
while(ll[1]<rr[1]&&q[1][ll[1]]<i-n+1)++ll[1];
while(ll[1]<rr[1]&&d[j][q[1][rr[1]-1]]<=d[j][i])--rr[1];
q[1][rr[1]++]=i;
mx[j][i]=d[j][q[1][ll[1]]];
}
}
for(int j=n;j<=b;++j)
{
ll[0]=ll[1]=rr[0]=rr[1]=1;
q[0][1]=q[1][1]=0;
for(int i=1;i<=a;++i)
{
while(ll[0]<rr[0]&&q[0][ll[0]]<i-n+1)++ll[0];
while(ll[0]<rr[0]&&mi[q[0][rr[0]-1]][j]>=mi[i][j])--rr[0];
q[0][rr[0]++]=i;
while(ll[1]<rr[1]&&q[1][ll[1]]<i-n+1)++ll[1];
while(ll[1]<rr[1]&&mx[q[1][rr[1]-1]][j]<=mx[i][j])--rr[1];
q[1][rr[1]++]=i;
if(i>=n)ans=min(ans,mx[q[1][ll[1]]][j]-mi[q[0][ll[0]]][j]);
}
}
printf("%d",ans);
return 0;
}
洛谷P2219 [HAOI2007]修筑绿化带
时空限制 1000ms / 128MB
题目描述
为了增添公园的景致,现在需要在公园中修筑一个花坛,同时在画坛四周修建一片绿化带,让花坛被绿化带围起来。
如果把公园看成一个MN的矩形,那么花坛可以看成一个CD的矩形,绿化带和花坛一起可以看成一个AB的矩形。
如果将花园中的每一块土地的“肥沃度”定义为该块土地上每一个小块肥沃度之和,那么,
绿化带的肥沃度=AB块的肥沃度-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
题目分析
和上面那题大同小异
预处理每个C*D 和 AB 矩阵的分数和
单调队列求每个(A-C-1)*(B-D-1)大小矩阵中AB矩阵的分数最大值
对每个以i,j为右下角的C*D 更新一次答案即可
注意绿化带是修建在花坛四周的,单调队列处理的矩阵大小要减一
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=2010;
int n,m,A,B,C,D;
int val[maxn][maxn],sum[maxn][maxn];
int f[maxn][maxn],g[maxn][maxn];
int q[maxn],ll,rr;
int mx[maxn][maxn],mx2[maxn][maxn];
int main()
{
n=read();m=read();
A=read();B=read();C=read();D=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
val[i][j]=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+val[i][j];
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
if(i>=C&&j>=D) f[i][j]=sum[i][j]-sum[i-C][j]-sum[i][j-D]+sum[i-C][j-D];
if(i>=A&&j>=B) g[i][j]=sum[i][j]-sum[i-A][j]-sum[i][j-B]+sum[i-A][j-B];
}
int lim=B-D-1;
for(int i=1;i<=n+(A-C);++i)
{
ll=rr=1;
for(int j=1;j<=m+(B-D);++j)
{
while(ll<rr&&j-q[ll]+1>lim) ll++;
while(ll<rr&&g[i][j]>=g[i][q[rr-1]]) rr--;
q[rr++]=j;
if(j>=lim) mx[i][j]=g[i][q[ll]];
}
}
lim=A-C-1;
for(int j=1;j<=m+(B-D);++j)
{
ll=rr=1;
for(int i=1;i<=n+(A-C);++i)
{
while(ll<rr&&i-q[ll]+1>lim) ll++;
while(ll<rr&&mx[i][j]>=mx[q[rr-1]][j]) rr--;
q[rr++]=i;
if(i>=lim) mx2[i][j]=mx[q[ll]][j];
}
}
int ans=0;
for(int i=C;i<n;++i)
for(int j=D;j<m;++j)
ans=max(ans,mx2[i+(A-C)-1][j+(B-D)-1]-f[i][j]);
printf("%d",ans);
return 0;
}