bzoj1047 [HAOI2007]理想的正方形
阿新 • • 發佈:2017-06-14
iostream page 同時 最小整數 sta 隊列 pan 之間 最大
Submit: 3311 Solved: 1819
[Submit][Status][Discuss]
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
1047: [HAOI2007]理想的正方形
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3311 Solved: 1819
[Submit][Status][Discuss]
Description
有一個a*b的整數組成的矩陣,現請你從中找出一個n*n的正方形區域,使得該區域所有數中的最大值和最小值
的差最小。
Input
第一行為3個整數,分別表示a,b,n的值第二行至第a+1行每行為b個非負整數,表示矩陣中相應位置上的數。每
行相鄰兩數之間用一空格分隔。
100%的數據2<=a,b<=1000,n<=a,n<=b,n<=1000
Output
僅一個整數,為a*b矩陣中所有“n*n正方形區域中的最大整數和最小整數的差值”的最小值。
Sample Input
5 4 21 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
Sample Output
1 分析:數據這麽大,直接搜肯定是不行的.可以發現這道題就是滑動的窗口的二維版本,只不過要同時求出最大值和最小值罷了,那麽就可以用單調隊列來求. 那麽二維的單調隊列該怎麽寫呢?其實對於一維轉二維的問題,我們只需要先單獨處理行或列,然後將處理好的看作是一個元素,然後轉化為一維進行處理. 在這裏,我們先求出每一列的單調隊列,用數組記錄下以(i,j)為最下面的一個元素的長度為n的當前列的元素的最大值或最小值(有點繞),然後利用求出來的數組在每一行上求單調隊列,最後統計出答案.#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> const int inf = 1000000000; using namespace std; int a, b, n, map[1010][1010], q1[1010], q2[1010], num1[1010], num2[1010], maxx[1010][1010], minx[1010][1010], ans = inf; void solve1() { int l1, r1, l2, r2; for (intj = 1; j <= b; j++) { l1 = l2 = 1; r1 = r2 = 0; for (int i = 1; i <= a; i++) { //隊列1 while (l1 <= r1 && i - num1[l1] >= n) l1++; while (l1 <= r1 && q1[r1] < map[i][j]) r1--; q1[++r1] = map[i][j]; num1[r1] = i; //隊列2 while (l2 <= r2 && i - num2[l2] >= n) l2++; while (l2 <= r2 && q2[r2] > map[i][j]) r2--; q2[++r2] = map[i][j]; num2[r2] = i; if (i >= n) { maxx[i][j] = q1[l1]; minx[i][j] = q2[l2]; } } } } void solve2() { int l1, r1, l2, r2; for (int i = 1; i <= a; i++) { l1 = l2 = 1; r1 = r2 = 0; for (int j = 1; j <= b; j++) { while (l1 <= r1 && j - num1[l1] >= n) l1++; while (l1 <= r1 && q1[r1] < maxx[i][j]) r1--; q1[++r1] = maxx[i][j]; num1[r1] = j; while (l2 <= r2 && j - num2[l2] >= n) l2++; while (l2 <= r2 && q2[r2] > minx[i][j]) r2--; q2[++r2] = minx[i][j]; num2[r2] = j; if (i >= n && j >= n) ans = min(ans, q1[l1] - q2[l2]); } } } int main() { scanf("%d%d%d", &a, &b, &n); for (int i = 1; i <= a;i++) for (int j = 1; j <= b; j++) scanf("%d", &map[i][j]); solve1(); solve2(); printf("%d", ans); return 0; }
bzoj1047 [HAOI2007]理想的正方形