您的位置:首页 > 其它

bzoj1047[HAOI2007]理想的正方形 单调队列

2017-10-12 17:23 363 查看
题意:有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

早就看过这题了,解法其实很简单啦,但是我单调队列经常打错,然后没什么信心去搞这题= =最后想了想还是要锻炼一下自己就来刚了一波。

这应该是一个二维单调队列一样的东西,具体的话就是单调队列求出每一个点往右n个的最小最大值。

然后每一次对于一个n*n的矩形,枚举他的长宽起点(或者终点,都一样),再用两个单调队列求一列上的差值最小,具体就是让mx尽量小,mn尽量大。

感觉收获颇丰。。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e3+5;
const int M=1e6+5;
const int inf=1e9;
int mp[N][N],n,m,k,l,r,ans,mx[N][N],mn[N][N];
int L1[N],L2[N],R1[N],R2[N],d1[N][N],d2[N][N];
int l1,r1,l2,r2,q1
,q2
;
int main()
{
scanf("%d%d%d",&n,&m,&k);
fo(i,1,n)
fo(j,1,m)scanf("%d",&mp[i][j]),L1[i]=L2[i]=1;
ans=inf;
fo(i,1,n)
{
l1=l2=1,r1=r2=0;
fd(j,m,1)
{
mx[i][j]=mn[i][j]=mp[i][j];
while(l1<=r1&&q1[l1]-j>=k)l1++;
while(l2<=r2&&q2[l2]-j>=k)l2++;

while(r1>=l1&&mp[i][j]>mp[i][q1[r1]])r1--;
q1[++r1]=j;
if (l1<=r1)mx[i][j]=max(mx[i][j],mp[i][q1[l1]]);

while(r2>=l2&&mp[i][j]<mp[i][q2[r2]])r2--;
q2[++r2]=j;
if (l2<=r2)mn[i][j]=min(mn[i][j],mp[i][q2[l2]]);
}
fd(j,m-k+1,1)
{
while(L1[j]<=R1[j]&&i-d1[j][L1[j]]>=k)L1[j]++;
while(L2[j]<=R2[j]&&i-d2[j][L2[j]]>=k)L2[j]++;
while(L1[j]<=R1[j]&&mx[i][j]>mx[d1[j][R1[j]]][j])R1[j]--;
while(L2[j]<=R2[j]&&mn[i][j]<mn[d2[j][R2[j]]][j])R2[j]--;
d1[j][++R1[j]]=i;
d2[j][++R2[j]]=i;
if (i>=k)
{
if (L1[j]<=R1[j]&&L2[j]<=R2[j])
ans=min(ans,mx[d1[j][L1[j]]][j]-mn[d2[j][L2[j]]][j]);
}
}
}

printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: