[HAOI2007]理想的正方形

嘟嘟嘟

 

这题一种做法是单调队列,像二维的滑动窗口。或是二维st表。我用的是第二种方法。

 

首先预处理的时候,对于一个边长为2k的正方形的最大值(最小值同理),应该由位于这个正方形的四个角上的边长为2k-1的小正方形转化而来。令Maxi,j,k表示左上角为(i, j) 的边长为2k的正方形的最大值,则

Maxi,j,k = max(Maxi,j,k - 1, Maxi,j + (1 << (k - 1)),k - 1, Maxi + (1 << (k - 1)),j,k - 1, Maxi + (1 << (k - 1)),j + (1 << (k - 1)),k - 1);

 

查询的时候,我们先求一个值kn,表示在2k <= n的前提下k的最大值。求完这个就像一维st表那样,只不过从这个n * n的正方形的四个角所在的小正方形转化而来,如下图

 

这个n * n的正方形的最大值就由这四个小正方形最大值转化而来。

这样转移方程就出来了

maxx = max(Maxi,j,kn, Maxi,j + n - (1 << kn),kn, Maxi + n - (1 << kn),j,kn, Maxi + n - (1 << kn),j + n - (1 << kn),kn)

有一个小优化就是预处理的时候k只用枚举到kn,而不是到(1 << k) == min(a, b).

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<stack>
 8 #include<queue>
 9 #include<vector>
10 #include<cctype>
11 using namespace std;
12 #define enter puts("")
13 #define space putchar(' ')
14 #define Mem(a) memset(a, 0, sizeof(a))
15 typedef long long ll;
16 typedef double db;
17 const int INF = 0x3f3f3f3f;
18 const db eps = 1e-8;
19 const int maxn = 1e3 + 5;
20 inline ll read()
21 {
22     ll ans = 0;
23     char ch = getchar(), last = ' ';
24     while(!isdigit(ch)) {last = ch; ch = getchar();}
25     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
26     if(last == '-') ans = -ans;
27     return ans;
28 }
29 inline void write(ll x)
30 {
31     if(x < 0) putchar('-'), x = -x;
32     if(x >= 10) write(x / 10);
33     putchar(x % 10 + '0');
34 }
35 
36 int x, y, n, a[maxn][maxn];
37 
38 int Max[maxn][maxn][7], Min[maxn][maxn][7], nk;
39 void rmq()
40 {
41     for(int i = 1; i <= x; ++i)
42         for(int j = 1; j <= y; ++j) Max[i][j][0] = Min[i][j][0] = a[i][j];
43     for(int k = 1; (1 << k) <= n; ++k)
44         for(int i = 1; i + (1 << k) - 1 <= x; ++i)
45             for(int j = 1; j + (1 << k) - 1 <= y; ++j)
46             {
47                 Max[i][j][k] = max(max(Max[i][j][k - 1], Max[i][j + (1 << (k - 1))][k - 1]), max(Max[i + (1 << (k - 1))][j][k - 1], Max[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]));
48                 Min[i][j][k] = min(min(Min[i][j][k - 1], Min[i][j + (1 << (k - 1))][k - 1]), min(Min[i + (1 << (k - 1))][j][k - 1], Min[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]));
49             }
50     while((1 << (nk + 1)) <= n) nk++;
51 }
52 
53 int ans = 2147483647;
54 
55 int main()
56 {
57     x = read(); y = read(); n = read();
58     for(int i = 1; i <= x; ++i)
59         for(int j = 1; j <= y; ++j) a[i][j] = read();
60     rmq();
61     for(int i = 1; i <= x - n + 1; ++i)
62         for(int j = 1; j <= y - n + 1; ++j)
63         {
64             int _max = max(max(Max[i][j][nk], Max[i][j + n - (1 << nk)][nk]), max(Max[i + n - (1 << nk)][j][nk], Max[i + n - (1 << nk)][j + n - (1 << nk)][nk]));
65             int _min = min(min(Min[i][j][nk], Min[i][j + n - (1 << nk)][nk]), min(Min[i + n - (1 << nk)][j][nk], Min[i + n - (1 << nk)][j + n - (1 << nk)][nk]));
66             ans = min(ans, _max - _min);
67         }
68     write(ans); enter;
69     return 0;
70 }
View Code
原文地址:https://www.cnblogs.com/mrclr/p/9511772.html