[BZOJ 1047]理想的正方形
Link:
Solution:
(1)先横向用单调队列求出每个数左边$n$个数中的最值
(2)再纵向利用横向的结果用单调队列进行相同的操作
通过以上操作将$a*b$的矩阵转化为了$(a-n+1)*(b-n+1)$的矩阵
相当于每个正方形被缩成了一个点,而每个点的最值就代表着原正方形中的最值
Tip:
1、又被$1<<27$坑了……以后还是都设为$1<<30$吧
2、将二维转化为两个一维的合并的思想很劲啊,和二维数据结构的处理方式很类似啊
Code:
#include <bits/stdc++.h> using namespace std; const int MAXN=1005;//res的初始值一定要设大,如果上限为1e9则要设为(1<<30) int q1[MAXN],q2[MAXN],l1,l2,r1,r2,res=1<<30; int n,m,k,dat[MAXN][MAXN],mx[MAXN][MAXN],mn[MAXN][MAXN]; int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&dat[i][j]),mx[i][j]=mn[i][j]=dat[i][j]; for(int i=1;i<=n;i++) { l1=l2=1;r1=r2=0; for(int j=1;j<=m;j++) { while(l1<=r1&&j-q1[l1]>=k) l1++; while(l2<=r2&&j-q2[l2]>=k) l2++; while(l1<=r1&&dat[i][j]>dat[i][q1[r1]]) r1--; while(l2<=r2&&dat[i][j]<dat[i][q2[r2]]) r2--; q1[++r1]=j;mx[i][j]=max(mx[i][j],dat[i][q1[l1]]); q2[++r2]=j;mn[i][j]=min(mn[i][j],dat[i][q2[l2]]); } } for(int i=k;i<=m;i++) { l1=l2=1;r1=r2=0; for(int j=1;j<=n;j++) { while(l1<=r1&&j-q1[l1]>=k) l1++; while(l2<=r2&&j-q2[l2]>=k) l2++; while(l1<=r1&&mx[j][i]>mx[q1[r1]][i]) r1--; while(l2<=r2&&mn[j][i]<mn[q2[r2]][i]) r2--; q1[++r1]=j;q2[++r2]=j; //要保证j>=k if(j>=k) res=min(res,mx[q1[l1]][i]-mn[q2[l2]][i]); } } printf("%d",res); return 0; }