理想的正方形
理想的正方形
二维倍增
SCUACM2022集训前训练-动态规划 - Virtual Judge (vjudge.net)
设 \(maxn[i][j][k]\) 为以 \((i,j)\) 为左上角,边长为 \(2^k\) 的正方形内元素的最大值
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10;
int n, m, len, Log[N];
int maxn[N][N][15], minn[N][N][15];
int a[N][N];
void init()
{
for (int i = 2; i < N; i++)
Log[i] = Log[i / 2] + 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
maxn[i][j][0] = minn[i][j][0] = a[i][j];
for (int k = 1; k <= 12; k++)
{
for (int i = 1; i + (1 << k) - 1 <= n; i++)
{
for (int j = 1; j + (1 << k) - 1 <= m; j++)
{
int t1, t2, t3, t4;
t1 = maxn[i][j][k-1];
t2 = maxn[i + (1 << k - 1)][j][k-1];
t3 = maxn[i][j + (1 << k - 1)][k-1];
t4 = maxn[i + (1 << k - 1)][j + (1 << k - 1)][k-1];
maxn[i][j][k] = max({t1, t2, t3, t4});
t1 = minn[i][j][k-1];
t2 = minn[i + (1 << k - 1)][j][k-1];
t3 = minn[i][j + (1 << k - 1)][k-1];
t4 = minn[i + (1 << k - 1)][j + (1 << k - 1)][k-1];
minn[i][j][k] = min({t1, t2, t3, t4});
}
}
}
}
int query(int sx, int sy, int len)
{
int k = Log[len];
int ex = sx + len - 1, ey = sy + len - 1;
int t1, t2, t3, t4;
t1 = maxn[sx][sy][k];
t2 = maxn[sx][ey + 1 - (1 << k)][k];
t3 = maxn[ex + 1 - (1 << k)][sy][k];
t4 = maxn[ex + 1 - (1 << k)][ey + 1 - (1 << k)][k];
int mx = max({t1, t2, t3, t4});
t1 = minn[sx][sy][k];
t2 = minn[sx][ey + 1 - (1 << k)][k];
t3 = minn[ex + 1 - (1 << k)][sy][k];
t4 = minn[ex + 1 - (1 << k)][ey + 1 - (1 << k)][k];
int mn = min({t1, t2, t3, t4});
// cout << sx << " " << sy << ": " << mx << " " << mn << endl;
return mx - mn;
}
int main()
{
scanf("%d%d%d", &n, &m, &len);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &a[i][j]);
init();
int ans = 2e9;
for (int sx = 1; sx + len - 1 <= n; sx++)
for (int sy = 1; sy + len - 1 <= m; sy++)
ans = min(ans, query(sx, sy, len));
printf("%d\n", ans);
return 0;
}