牛客网暑期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;
}

 

posted @ 2018-08-10 10:02  鬼沐冢  阅读(362)  评论(0编辑  收藏  举报