https://nanti.jisuanke.com/t/42391

题意:给出两个n* m矩阵,两个矩阵都为1到n* m的一种排列,求两个矩阵的最大相同子矩阵。

对于第二个矩阵的每一个位置,仅当相邻点在第一个矩阵中也相邻,才能拓展,处理出该点向由拓展出的最远长度。

则变为如下图,有一些线段,求最大矩形。

我们可以一列一列地枚举,但对于每一列,只能线性地求最大矩阵。

可以建立一个单调栈,由上到下地放入线段,初始时把第一个线段放进栈中。仅当下一条线段的长度比栈顶长或一样长时,栈顶线段可以继续向下拓展。否则对栈顶线段进行结算并弹出。

还有一种不合法的情况,由于预处理只判断了横向拓展,所以第二个矩阵中同一列的可能在第一个矩阵中并不是同一列,或者第二个矩阵中两行相邻的在第一个矩阵中不相邻,这时要把栈整个清空结算。

注意当弹出栈顶时,预留的空间仍是存在的,因此实际压入栈中的位置也要改变。

最后还要再结算一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 10;
int n, m;
int a[1010][1010], b[1010][1010];
int dp[1010][1010];
int r[maxn], px[maxn], py[maxn];
stack<int>st;
int ans;
int vis[1010];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%d", &a[i][j]);
px[a[i][j]] = i;
py[a[i][j]] = j;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%d", &b[i][j]);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j < m; j++) {
r[a[i][j]] = a[i][j + 1];
}
}
for (int i = 1; i <= n; i++) {
dp[i][m] = 1;
for (int j = m - 1; j >= 1; j--) {
if (r[b[i][j]] == b[i][j + 1]) {
dp[i][j] = dp[i][j + 1] + 1;
}
else dp[i][j] = 1;
}
}
for (int j = 1; j <= m; j++) {
while (!st.empty())st.pop();
fill(vis, vis + n + 1, 0);
for (int i = 1; i <= n; i++) {
if (!st.empty() && (py[b[st.top()][j]] != py[b[i][j]] || !vis[px[b[i][j]] - 1])) { //不合法,整个清空
while (!st.empty()) {
ans = max(ans, dp[st.top()][j] * (i - vis[px[b[st.top()][j]]]));
vis[px[b[st.top()][j]]] = 0;
st.pop();
}
}
int tmp = i;
while (!st.empty() && dp[st.top()][j] > dp[i][j]) { //合法,逐个判断,保持单调性
ans = max(ans, dp[st.top()][j] * (i - vis[px[b[st.top()][j]]]));
tmp = vis[px[b[st.top()][j]]];
st.pop();
}
st.push(i);
vis[px[b[i][j]]] = tmp;
}
while (!st.empty()) {
ans = max(ans, (n + 1 - vis[px[b[st.top()][j]]])*dp[st.top()][j]);
st.pop();
}
}
printf("%d\n", ans);
return 0;
}