本文最后更新于 2295 天前,其中的信息可能已经有所发展或是发生改变。
Table of Content
题解
注意 这和数独不一样,是要求子矩阵中每一行 或 每一列的字符只出现一次
这个问题坑了不少人
剩下的按照官方题解就完成
• 注意到52种字符,子矩形最多52行,52列。
• 一个5252nm的做法是显然的,可以优化到52*nm。
• 枚举上下边界(最多差52)
• 当左端点确定后,右端点的范围是连续的一段,并且单调
• 扫一遍即可,可以使用位运算降低复杂度。
AC代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <array>
using namespace std;
using ll = long long;
const int maxn = 1000 + 10;
int n, m;
char s[maxn][maxn];
int horizontal[maxn][maxn], vertical[maxn][maxn];
array<int, maxn> pos, len;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> (s[i] + 1);
pos.fill(0);
for (int j = 1; j <= m; ++j) {
horizontal[i][j] = min(horizontal[i][j - 1] + 1, j - pos[s[i][j]]);
pos[s[i][j]] = j;
}
}
for (int j = 1; j <= m; ++j) {
pos.fill(0);
for (int i = 1; i <= n; ++i) {
vertical[i][j] = min(vertical[i - 1][j] + 1, i - pos[s[i][j]]);
pos[s[i][j]] = i;
}
}
ll ans = 0;
for (int j = 1; j <= m; ++j) {
len.fill(0);
for (int i = 1; i <= n; ++i) {
for (int k = 0; k < horizontal[i][j]; ++k) {
len[k] = min(len[k] + 1, vertical[i][j - k]);
if (k) len[k] = min(len[k], len[k - 1]);
ans += len[k];
}
for (int k = horizontal[i][j]; k < 54; k++) len[k] = 0;
}
}
cout << ans << '\n';
}