BZOJ 1047: [HAOI2007]理想的正方形( 单调队列 )
单调队列..先对每一行扫一次维护以每个点(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 MBSubmit: 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