1. 程式人生 > >洛谷P2216 【HAOI2007】 理想的正方形

洛谷P2216 【HAOI2007】 理想的正方形

題目傳送門

感覺這還是一道挺不錯的題的。這道題的思路是先處理行的最大值和最小值,再用行的最值處理一遍列的最值,如果要這一遍求的同時也是以這個位置為右下角的正方形的最值,那我們需要兩次處理都使用滑動視窗,而且要兩個同時跑。

不會滑動視窗的請自行百度qwq

具體細節及變數解釋見程式碼

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=1000000000;
const int N=1010;
struct node
{
    int
id,data; }x[N],y[N];//x和y陣列為滑動視窗用的單調佇列,一個單調增一個單調減,id記錄入隊時間(其實就是位置) int n,m,q,ans=INF,a[N][N],maxn[2][N][N],minn[2][N][N];// //n和m為原矩陣大小(a和b),q為求的正方形大小(題目中的k) //maxn[0]和minn[0]記錄第一次處理的結果,maxn[1]和minn[1]記錄第二次處理的結果 int read() { char ch=getchar();int sum=0; while(ch<'0'||ch>'9')ch=getchar(); while
(ch>='0'&&ch<='9')sum=(sum<<3)+(sum<<1)+ch-'0',ch=getchar(); return sum; }//快讀 int main() { n=read();m=read();q=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read(); for(int i=1;i<=n;i++) //第一次處理,maxn[0][i][j]記錄第i行中以到第j個數結束的連續q(或者k)個數的最大值,minn類似
{ int fx=1,fy=1,rx=0,ry=0; for(int j=1;j<=m;j++) { int t=a[i][j]; if(x[fx].id<max(0,j-q+1))fx++;if(y[fy].id<max(0,j-q+1))fy++; while(fx<=rx&&x[rx].data<t)rx--;x[++rx].data=t;x[rx].id=j; while(fy<=ry&&y[ry].data>t)ry--;y[++ry].data=t;y[ry].id=j;//以上為兩個滑動視窗 maxn[0][i][j]=x[fx].data;minn[0][i][j]=y[fy].data;//更新陣列 } } for(int j=1;j<=m;j++)//第二次處理,基本同第一次 { int fx=1,fy=1,rx=0,ry=0; for(int i=1;i<=n;i++) { int t=maxn[0][i][j],s=minn[0][i][j]; if(x[fx].id<max(0,i-q+1))fx++;if(y[fy].id<max(0,i-q+1))fy++; while(fx<=rx&&x[rx].data<t)rx--;x[++rx].data=t;x[rx].id=i; while(fy<=ry&&y[ry].data>s)ry--;y[++ry].data=s;y[ry].id=i; maxn[1][i][j]=x[fx].data;minn[1][i][j]=y[fy].data; } } for(int i=q;i<=n;i++) for(int j=q;j<=m;j++) ans=min(ans,maxn[1][i][j]-minn[1][i][j]);//找到最優解 printf("%d\n",ans);return 0; }