P2216 [HAOI2007]理想的正方形 单调队列
作者:互联网
题目描述
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
输入格式
第一行为3个整数,分别表示a,b,n的值
第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
输出格式
仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。
输入输出样例
输入 #15 4 2 1 2 5 6 0 17 16 0 16 17 2 1 2 10 2 1 1 2 2 2输出 #1
1
说明/提示
问题规模
(1)矩阵中的所有数都不超过1,000,000,000
(2)20%的数据2<=a,b<=100,n<=a,n<=b,n<=10
(3)100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// const int N=1000+10; int mp[N][N],maxx[N][N],minn[N][N],n,m,k; int de[N],de2[N]; int main() { cin>>n>>m>>k; rep(i,1,n)rep(j,1,m)scanf("%d",&mp[i][j]),maxx[i][j]=0,minn[i][j]=0; rep(i,1,n) { int l=1,r=0,l2=1,r2=0; rep(j,1,k) { while(l<=r&&mp[i][de[r]]>=mp[i][j])r--; de[++r]=j; while(l2<=r2&&mp[i][de2[r2]]<=mp[i][j])r2--; de2[++r2]=j; } minn[i][1]=mp[i][de[l]]; maxx[i][1]=mp[i][de2[l]]; rep(j,2,m-k+1) { while(l<=r&&mp[i][de[r]]>=mp[i][j+k-1])r--; while(l2<=r2&&mp[i][de2[r2]]<=mp[i][j+k-1])r2--; de[++r]=j+k-1; de2[++r2]=j+k-1; if(l<=r&&de[l]<j)l++; if(l2<=r2&&de2[l2]<j)l2++; minn[i][j]=mp[i][de[l]]; maxx[i][j]=mp[i][de2[l2]]; } } rep(j,1,m) { int l=1,r=0,l2=1,r2=0; rep(i,1,k) { while(l<=r&&minn[de[r]][j]>=minn[i][j])r--; de[++r]=i; while(l2<=r2&&maxx[de2[r2]][j]<=maxx[i][j])r2--; de2[++r2]=i; } minn[1][j]=minn[de[l]][j]; maxx[1][j]=maxx[de2[l2]][j]; rep(i,2,n-k+1) { while(l<=r&&minn[de[r]][j]>=minn[i+k-1][j])r--; while(l2<=r2&&maxx[de2[r2]][j]<=maxx[i+k-1][j])r2--; de[++r]=i+k-1; de2[++r2]=i+k-1; if(l<=r&&de[l]<i)l++; if(l2<=r2&&de2[l2]<i)l2++; minn[i][j]=minn[de[l]][j]; maxx[i][j]=maxx[de2[l2]][j]; } } int ans=inf; rep(i,1,n-k+1) rep(j,1,m-k+1) ans=min(ans,maxx[i][j]-minn[i][j]); cout<<ans; return 0; }View Code
标签:队列,rep,矩阵,整数,HAOI2007,while,P2216,l2,define 来源: https://www.cnblogs.com/bxd123/p/11393926.html