洛谷OJ 2216 理想的正方形 单调队列(二维)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷OJ 2216 理想的正方形 单调队列(二维)相关的知识,希望对你有一定的参考价值。
https://www.luogu.org/problem/show?pid=2216
题意:给出a*b矩形 从中找到一个n*n正方形,其(最大值-最小值之差)最小,a,b<=1e3,n<=100
暴力枚举正方形右下角,如何快速算出其最大值和最小值?
先用单调队列预处理出ma[i][j] 表示(i,j)以第i行j列结尾长度为n的最大值
/在枚举列之后,对同一个列,由于已经知道该列 每行长度为n的最值 则在次利用单调队列,从上往下扫描行,求出(i,j)为右下角的矩形的最值即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=9999973; const int N=2e3+20; int c[N][N],a,b,n; int ma[N][N],mi[N][N],q[N],d[N]; void init() { //l=r队列为空 r指向最后一个元素的下一个 for(int i=1;i<=a;i++) { int l=1,r=1; for(int j=1;j<=b;j++) { while(l<r&&j-d[l]>=n) l++;//淘汰过时元素 while(l<r&&q[r-1]<=c[i][j]) r--;//保持单调 d[r]=j;//记录下标 q[r++]=c[i][j]; if(j>=n) ma[i][j]=q[l]; } memset(d,0,sizeof(d)); l=1,r=1; for(int j=1;j<=b;j++) { while(l<r&&j-d[l]>=n) l++;// while(l<r&&q[r-1]>=c[i][j]) r--; d[r]=j; q[r++]=c[i][j]; if(j>=n) mi[i][j]=q[l]; } } } int tx[N],ti[N]; void calc() { int ans=1e9; for(int j=n;j<=b;j++)//固定列 { int l=0,r=0; for(int i=1;i<=a;i++)//右下角坐标 { while(l<r&&q[r-1]<=ma[i][j]) r--;//预处理每行的长度为n中的最值后->相当于降维 while(l<r&&i-d[l]>=n) l++; q[r]=ma[i][j],d[r++]=i; if(i>=n) tx[i]=q[l];//(固定列后 右下角为(i,j)的正方形的最值) } memset(d,0,sizeof(d)); l=0,r=0; for(int i=1;i<=a;i++) { while(l<r&&q[r-1]>=mi[i][j]) r--; while(l<r&&i-d[l]>=n) l++; q[r]=mi[i][j],d[r++]=i; if(i>=n) ti[i]=q[l]; } for(int k=n;k<=a;k++) ans=min(ans,tx[k]-ti[k]); } cout<<ans<<endl; } int main() { while(cin>>a>>b>>n) { for(int i=1;i<=a;i++) for(int j=1;j<=b;j++) cin>>c[i][j]; init(); calc(); } return 0; }
以上是关于洛谷OJ 2216 理想的正方形 单调队列(二维)的主要内容,如果未能解决你的问题,请参考以下文章
[luoguP2216] [HAOI2007]理想的正方形(二维单调队列)