链接:https://www.nowcoder.com/acm/contest/145/J
来源:牛客网
You have a n * m grid of characters, where each character is an English letter (lowercase or uppercase, which means there are a total of 52 different possible letters).
A nonempty subrectangle of the grid is called sudoku-like if for any row or column in the subrectangle, all the cells in it have distinct characters.
How many sudoku-like subrectangles of the grid are there?
输入描述:
The first line of input contains two space-separated integers n, m (1 ≤ n, m ≤ 1000). The next n lines contain m characters each, denoting the characters of the grid. Each character is an English letter (which can be either uppercase or lowercase).
输出描述:
Output a single integer, the number of sudoku-like subrectangles.
示例1
输入
复制
2 3 AaA caa
输出
复制
11
题意:给出一个字符矩阵,只包含大小写字母,问有多少个子矩阵为字符数独(任意一行或一列没有重复字符)。
注意到一共只有52个不同字符,如果枚举每一个左上端点,然后做52*52的暴力一定可以得出答案但是也一定会超时,所以先预处理出每一个位置可以向右和向下延伸的最大值,然后还是n*m遍历所有左端点,但是计数复杂度优化成了52。
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
#define ll long long
const int maxm = 1005;
int r[maxm][maxm], c[maxm][maxm], s[maxm][maxm], flag[maxm];
char str[maxm][maxm];
int main()
{
int n, i, j, k, sum, m, cnt = 0;
ll ans = 0;
scanf("%d%d", &n, &m);
for (i = 1;i <= n;i++)
scanf("%s", str[i] + 1);
for (i = 1;i <= n;i++)
{
for (j = 1;j <= m;j++)
{
cnt++;
for (k = j;k <= min(j + 52 - 1, m);k++)
{
if (flag[str[i][k]] == cnt)
break;
flag[str[i][k]] = cnt;
}
r[i][j] = k - j;
cnt++;
for (k = i;k <= min(i + 52 - 1, n);k++)
{
if (flag[str[k][j]] == cnt)
break;
flag[str[k][j]] = cnt;
}
c[i][j] = k - i;
}
}
for (i = 1;i <= n;i++)
{
for (j = 1;j <= m;j++)
{
s[i][j] = c[i][j];
int e = j + r[i][j] - 1, now;
for (k = j + 1;k <= e;k++)
s[i][k] = min(s[i][k - 1], c[i][k]);
ans += r[i][j];
e = c[i][j] + i - 1, now = j + r[i][j] - 1;
for (k = i + 1;k <= e;k++)
{
now = min(now, j + r[k][j] - 1);
while (s[i][now] < k - i + 1 && now >= j)
now--;
if (now < j) break;
ans += now - j + 1;
}
}
}
printf("%lld\n", ans);
return 0;
}