单调队列..先对每一行扫一次维护以每个点(x, y)为结尾的长度为n的最大最小值.然后再对每一列扫一次, 在之前的基础上维护(x, y)为结尾的长度为n的最大最小值. 时间复杂度O(ab)
(话说还是deque2048ms快..list3572ms慢死了)
#include<bits/stdc++.h> using namespace std; const int maxn = 1009; int X[maxn][maxn], R, C, N;
int MN[maxn][maxn], MX[maxn][maxn];
deque<int> MIN, MAX; int main() { cin >> R >> C >> N;
for(int i = 0; i < R; i++)
for(int j = 0; j < C; j++)
scanf("%d", &X[i][j]); for(int i = 0; i < R; i++) {
MIN.clear(); MAX.clear();
for(int j = 0; j < C; j++) {
while(!MIN.empty() && MIN.front() + N <= j) MIN.pop_front();
while(!MAX.empty() && MAX.front() + N <= j) MAX.pop_front();
while(!MIN.empty() && X[i][MIN.back()] >= X[i][j]) MIN.pop_back();
while(!MAX.empty() && X[i][MAX.back()] <= X[i][j]) MAX.pop_back();
MIN.push_back(j);
MAX.push_back(j);
if(j + 1 >= N) {
MN[i][j - N + 1] = X[i][MIN.front()];
MX[i][j - N + 1] = X[i][MAX.front()];
}
}
} int ans = 2000000000;
for(int j = 0; j + N <= C; j++) {
MIN.clear(); MAX.clear();
for(int i = 0; i < R; i++) {
while(!MIN.empty() && MIN.front() + N <= i) MIN.pop_front();
while(!MAX.empty() && MAX.front() + N <= i) MAX.pop_front();
while(!MIN.empty() && MN[MIN.back()][j] >= MN[i][j]) MIN.pop_back();
while(!MAX.empty() && MX[MAX.back()][j] <= MX[i][j]) MAX.pop_back();
MIN.push_back(i);
MAX.push_back(i);
if(i + 1 >= N)
ans = min(ans, MX[MAX.front()][j] - MN[MIN.front()][j]);
}
}
printf("%d\n", ans); return 0;
}
1047: [HAOI2007]理想的正方形
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 2058 Solved: 1093
[Submit][Status][Discuss]
Description
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
Input
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
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
HINT
问题规模
(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