BZOJ 1047: [HAOI2007]理想的正方形
思路:
二维单调队列
先用单调队列预处理出每个位置在这一行往前n个位置的最大值最小值,然后O(n^2)扫过去,对列用单调队列
#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pi acos(-1.0) #define LL long long //#define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pii pair<int, int> #define piii pair<pii, int> #define mem(a, b) memset(a, b, sizeof(a)) #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout); //head const int N = 1e3 + 5; const int INF = 0x7f7f7f7f; int num[N][N], mx[N][N], mn[N][N]; int main() { int a, b, n; scanf("%d %d %d", &a, &b, &n); for (int i = 1; i <= a; i++) { for (int j = 1; j <= b; j++) { scanf("%d", &num[i][j]); } } deque<int>q1, q2; for (int i = 1; i <= a; i++) { q1.clear(); q2.clear(); for (int j = 1; j <= b; j++) { while(!q1.empty() && num[i][q1.back()] >= num[i][j]) q1.pop_back(); q1.push_back(j); while(!q1.empty() && q1.front() < j - n + 1) q1.pop_front(); mn[i][j] = num[i][q1.front()]; while(!q2.empty() && num[i][q2.back()] <= num[i][j]) q2.pop_back(); q2.push_back(j); while(!q2.empty() && q2.front() < j - n + 1) q2.pop_front(); mx[i][j] = num[i][q2.front()]; } } int ans = INF; for (int j = n; j <= b; j++) { q1.clear(); q2.clear(); for (int i = 1; i <= a; i++) { while(!q1.empty() && mn[q1.back()][j] >= mn[i][j]) q1.pop_back(); q1.push_back(i); while(!q1.empty() && q1.front() < i - n + 1) q1.pop_front(); while(!q2.empty() && mx[q2.back()][j] <= mx[i][j]) q2.pop_back(); q2.push_back(i); while(!q2.empty() && q2.front() < i - n + 1) q2.pop_front(); if(i >= n) { ans = min(ans, mx[q2.front()][j] - mn[q1.front()][j]); } } } printf("%d\n", ans); return 0; }