牛客网暑期ACM多校训练营(第七场):J-Sudoku Subrectangles
链接:J-Sudoku Subrectangles
题意:给出 n * m 的字母矩阵,公52种字母。求出不含重复元素的子矩阵的个数。
题解:
L[i][j]:s[i][j] ~ s[i][ j - L[i][j] ] 不含重复元素。
U[i][j]:s[i][j] ~ s[ i - U[i][j] ][j] 不含重复元素。
那么枚举每一个点 s[i][j] ,统计以该点为右下角的矩阵中有多少个满足条件。
#include <bits/stdc++.h> using namespace std; const double EPS = 1e-6; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; const int maxn = 1000 + 10; int n, m; char s[maxn][maxn]; int pos[maxn], L[maxn][maxn], U[maxn][maxn], len[maxn]; int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) scanf("%s", s[i] + 1); for(int i = 1; i <= n; i++){ memset(pos, 0, sizeof(pos)); for(int j = 1; j <= m; j++){ L[i][j] = min(L[i][j-1] + 1, j - pos[s[i][j]]); pos[s[i][j]] = j; } } for(int j = 1; j <= m; j++){ memset(pos, 0, sizeof(pos)); for(int i = 1; i <= n; i++){ U[i][j] = min(U[i-1][j] + 1, i - pos[s[i][j]]); pos[s[i][j]] = i; } } long long ans = 0; for(int j = 1; j <= m; j++){ memset(len, 0, sizeof(len)); for(int i = 1; i <= n; i++){ for(int k = 0; k < L[i][j]; k++){ len[k] = min(len[k] + 1, U[i][j-k]); if(k) len[k] = min(len[k], len[k-1]); ans += len[k]; } for(int k = L[i][j]; k < 54; k++) len[k] = 0; } } printf("%lld\n", ans); return 0; }