牛客多校7 J Sudoku Subrectangles

链接:https://www.nowcoder.com/acm/contest/145/J
来源:牛客网

Sudoku Subrectangles
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
Special Judge, 64bit IO Format: %lld
题目描述
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
说明
For simplicity, denote the j-th character on the i-th row as (i, j).

For sample 1, there are 11 sudoku-like subrectangles. Denote a subrectangle
by (x1, y1, x2, y2), where (x1, y1) and (x2, y2) are the upper-left and lower-right coordinates of the subrectangle.

The sudoku-like subrectangles are (1, 1, 1, 1), (1, 2, 1, 2), (1, 3, 1, 3), (2, 1, 2, 1), (2, 2, 2, 2), (2, 3, 2, 3), (1, 1, 1, 2), (1, 2, 1, 3), (2, 1, 2, 2), (1, 1, 2, 1), (1, 3, 2, 3).
示例2
输入
复制
4 5
abcde
fGhij
klmno
pqrst
输出
复制
150
说明
For sample 2, the grid has 150 nonempty subrectangles, and all of them are sudoku-like.

预处理出每一个位置可以向右和向下延伸的最大值,再枚举每个左上端点,遍历计数,然后复杂度变成52 * n * m
转载:https://blog.csdn.net/zy704599894/article/details/81544049

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 1005;
char str[N][N];
int hang[N][N];
int lie[N][N];
int s[N][N];
int flag[N];

int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        for(int i = 1;i <= n;++i)
        {
            scanf("%s",str[i] + 1);
        }
        int tot = 0;
        memset(flag,0,sizeof(flag));
        //预处理每个子矩形左上端点,hang行最远能走到哪,lie列最远能走到哪
        for(int i = 1;i <= n;++i)
        {
            for(int j = 1;j <= m;++j)
            {
                tot++;
                int k;
                for(k = j;k <= min(j + 52 - 1,m);++k)
                {
                    if(flag[str[i][k]] == tot)
                        break;
                    flag[str[i][k]] = tot;
                }
                hang[i][j] = k - j;
                tot++;
                for(k = i;k <= min(i + 52 - 1,n);++k)
                {
                    if(flag[str[k][j]] == tot)
                        break;
                    flag[str[k][j]] = tot;
                }
                lie[i][j] = k - i;
            }
        }
        LL ans = 0;
        //枚举每个左上端点
        for(int i = 1;i <= n;++i)
        {
            for(int j = 1;j <= m;++j)
            {
                s[i][j] = lie[i][j];
                //预处理出当前(i,j)端点所在i行最远能走到哪(i,j)~(i,dis)的列值lie
                //s[i][k],代表前k - j个点的lie值最小值
                int dis = j + hang[i][j] - 1;
                for(int k = j + 1;k <= dis;++k)
                    s[i][k] = min(s[i][k - 1],lie[i][k]);
                //先将宽为1的矩形的个数加进去
                ans += hang[i][j];
                dis = i + lie[i][j] - 1;
                //接下来枚举矩形的宽,也就是枚举(i,j)点列最远能走到哪
                //now代表对应矩形相应宽度(也就是(i,j) ~ (dis,j))的最小长度
                //(i,now)相当于是矩形的右上端点
                int now = j + hang[i][j] - 1;
                for(int k = i + 1;k <= dis;++k)
                {
                    //取(i,j)~(k,j)的矩形的长度的最小值(也就是j + hang[k][j] - 1的最小值)
                    now = min(now,j + hang[k][j] - 1);
                    //如果矩形右上端点所能达到的宽度小于所枚举的宽度,则需要减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;
}

猜你喜欢

转载自blog.csdn.net/qq_36386435/article/details/81583227
今日推荐