BZOJ1047: [HAOI2007]理想的正方形(单调队列)
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值
的差最小。
题解:以前居然不会做????
这数据范围直接暴力就好了 先维护一下每行每n个数的最大最小值
再像滑窗一样每n行的统计一下答案就行了
#include <bits/stdc++.h> using namespace std; int n, m, k; int a[1005][1005]; int zd[1005]; int did[1005]; int zx[1005]; int xid[1005]; int mx[1005][1005]; int mi[1005][1005]; 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", &a[i][j]); for(int i = 1; i <= n; i++) { int top1 = 1, tail1 = 0; int top2 = 1, tail2 = 0; int cnt = 0; for(int j = 1; j <= m; j++) { zd[++tail1] = a[i][j]; did[tail1] = j; while(top1 != tail1 && zd[tail1] >= zd[tail1 - 1]) tail1--, zd[tail1] = a[i][j], did[tail1] = j; while(j - did[top1] + 1 > k) top1++; zx[++tail2] = a[i][j]; xid[tail2] = j; while(top2 != tail2 && zx[tail2] <= zx[tail2 - 1]) tail2--, zx[tail2] = a[i][j], xid[tail2] = j; while(j - xid[top2] + 1 > k) top2++; if(j >= k) mx[i][++cnt] = zd[top1], mi[i][cnt] = zx[top2]; } } int ans = 1e9; for(int i = 1; i <= m - k + 1; i++) { int top1 = 1, tail1 = 0; int top2 = 1, tail2 = 0; for(int j = 1; j <= n; j++) { zd[++tail1] = mx[j][i]; did[tail1] = j; while(top1 != tail1 && zd[tail1] >= zd[tail1 - 1]) tail1--, zd[tail1] = mx[j][i], did[tail1] = j; while(j - did[top1] + 1 > k) top1++; zx[++tail2] = mi[j][i]; xid[tail2] = j; while(top2 != tail2 && zx[tail2] <= zx[tail2 - 1]) tail2--, zx[tail2] = mi[j][i], xid[tail2] = j; while(j - xid[top2] + 1 > k) top2++; if(j >= k) ans = min(ans, zd[top1] - zx[top2]); } } printf("%d\n", ans); return 0; }