bzoj1047: [HAOI2007]理想的正方形
好神的单调栈啊。。。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,s,t) for(register int i=s;i<=t;i++) #define dwn(i,s,t) for(register int i=s;i>=t;i--) #define clr(x,c) memset(x,c,sizeof(x)) int read(){ int x=0;char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x; } const int nmax=1005; const int inf=0x7f7f7f7f; int a[nmax][nmax],n,m,b; int q[nmax],mx[nmax][nmax],mn[nmax][nmax],ans[nmax],res[nmax]; void solve(){ rep(i,1,n){ int l=1,r=0; rep(j,1,m) { if(q[l]<=j-b) l++; while(l<=r&&a[i][q[r]]<=a[i][j]) r--; q[++r]=j; if(j>=b) mx[i][j]=a[i][q[l]]; } l=1,r=0; rep(j,1,m){ if(q[l]<=j-b) l++; while(l<=r&&a[i][q[r]]>=a[i][j]) r--; q[++r]=j; if(j>=b) mn[i][j]=a[i][q[l]]; } } /*rep(i,1,n) { rep(j,b,m) printf("%d ",mx[i][j]);printf("\n"); } printf("\n"); rep(i,1,n){ rep(j,b,m) printf("%d ",mn[i][j]);printf("\n"); } printf("\n");*/ } void mins(int &a,int b){ if(a>b) a=b; } void work(){ int ret=inf; rep(j,b,m){ int l=1,r=0; rep(i,1,n) { if(q[l]<=i-b) l++; while(l<=r&&mx[q[r]][j]<=mx[i][j]) r--; q[++r]=i; if(i>=b) ans[i]=mx[q[l]][j]; } l=1,r=0; rep(i,1,n) { if(q[l]<=i-b) l++; while(l<=r&&mn[q[r]][j]>=mn[i][j]) r--; q[++r]=i; if(i>=b) res[i]=mn[q[l]][j]; } rep(i,b,n) mins(ret,ans[i]-res[i]); } printf("%d\n",ret); } int main(){ n=read(),m=read(),b=read(); rep(i,1,n) rep(j,1,m) a[i][j]=read(); solve();work(); return 0; }
1047: [HAOI2007]理想的正方形
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2702 Solved: 1465
[Submit][Status][Discuss]
Description
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值
的差最小。
Input
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每
行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100
Output
仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。
Sample Input
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
Sample Output
1