【HAOI2007】理想的正方形(RMQ)


题目链接:https://loj.ac/problem/10182

题目链接:https://www.luogu.com.cn/problem/P2216

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1047

做法

正解是单调队列,然而我太菜了,有时间再去研究单调队列做法。

二维st表预处理,复杂度$O(ablogn)$,n大的话$a$和$b$都跑不满,算算时间复杂度可以过

查询的时候O(1)查询就好了

预处理&查询

  • $st[i][j][k]$表示以$(i, j)$为左上角的长度为$2^k$的正方形的最值
  • 转移的时候每一个大的正方形可以由四个小正方形拼起来,查询的时候用四个$log(n)$的正方形覆盖起来

也没什么细节,这个做法比较简单比较好想。

代码

#include 
#include 
#include 
#include 
using namespace std;
inline int read() {
    int x = 0;
    char ch = getchar();
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return x;
}
const int maxN = 1005;
int a, b, n, stmax[maxN][maxN][11], stmin[maxN][maxN][11], K;
inline int max(int a, int b) { return a > b ? a : b; }
inline int min(int a, int b) { return a < b ? a : b; }
inline int Qmax(int i, int j) {
    return max(max(stmax[i][j][K], stmax[i + n - (1 << K)][j][K]),
               max(stmax[i][j + n - (1 << K)][K], stmax[i + n - (1 << K)][j + n - (1 << K)][K]));
}
inline int Qmin(int i, int j) {
    return min(min(stmin[i][j][K], stmin[i + n - (1 << K)][j][K]),
               min(stmin[i][j + n - (1 << K)][K], stmin[i + n - (1 << K)][j + n - (1 << K)][K]));
}
int main() {
    a = read(), b = read(), n = read();
    for (int i = 1; i <= a; ++i)
        for (int j = 1; j <= b; ++j) stmin[i][j][0] = read(), stmax[i][j][0] = stmin[i][j][0];
    K = log2(n);
    for (int k = 1; k <= K; ++k) {
        for (int i = 1; i + (1 << k) - 1 <= a; ++i) {
            for (int j = 1; j + (1 << k) - 1 <= b; ++j) {
                stmax[i][j][k] = max(stmax[i][j][k - 1], stmax[i + (1 << (k - 1))][j][k - 1]);
                stmax[i][j][k] = max(stmax[i][j][k], stmax[i][j + (1 << (k - 1))][k - 1]);
                stmax[i][j][k] = max(stmax[i][j][k], stmax[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]);

                stmin[i][j][k] = min(stmin[i][j][k - 1], stmin[i + (1 << (k - 1))][j][k - 1]);
                stmin[i][j][k] = min(stmin[i][j][k], stmin[i][j + (1 << (k - 1))][k - 1]);
                stmin[i][j][k] = min(stmin[i][j][k], stmin[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]);
            }
        }
    }
    int ans = 2e9;
    for (int i = 1; i <= a - n + 1; ++i) {
        for (int j = 1; j <= b - n + 1; ++j) {
            ans = min(ans, Qmax(i, j) - Qmin(i, j));
        }
    }
    cout << ans << '\n';
    return 0;
}