牛客网暑期ACM多校训练营(第七场)- J Sudoku Subrectangles

80 篇文章 0 订阅

https://www.nowcoder.com/acm/contest/145/J

题意:

让你求出有几个矩阵,他的行和列中的每个字母都不一样。注意 只要求一行中都不一样。

和一列中都不一样。

 

POINT:

预处理出一个点能往上,往左延伸的长度。

枚举矩阵的右下端点。

对于如何把n*m*52*52的效率优化一个52去掉。看代码注解

 

 

 

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1022;
char mp[N][N];
int lmax[N][N],umax[N][N],pos[N],len[N][N];
int n,m;
 
LL solve()
{
    for(int i=1;i<=n;i++){
        memset(pos,0,sizeof pos);
        for(int j=1;j<=m;j++){
            lmax[i][j]=min(lmax[i][j-1]+1,j-pos[mp[i][j]]);
            pos[mp[i][j]]=j;
        }
    }
    for(int j=1;j<=m;j++){
        memset(pos,0,sizeof pos);
        for(int i=1;i<=n;i++){
            umax[i][j]=min(umax[i-1][j]+1,i-pos[mp[i][j]]);
            pos[mp[i][j]]=i;
        }
    }
    LL ans=0;
    for(int j=1;j<=m;j++){
        memset(len[1],0,sizeof len[1]);
        for(int i=1;i<=n;i++){
            //确定了矩阵的右下角
 
            //len[i][y]代表(i,j-y)到(i,j)这段区间往上最大能到多少.
            //可以开一维,因为都是从上一层推下来,不过这样比较好懂.
            for(int l=0;l<lmax[i][j];l++){
                len[i][l]=min(umax[i][j-l],len[i-1][l]+1);//单纯(i,j-l)到(i,j)的区间可以往上到多少
                if(l)
                    len[i][l]=min(len[i][l],len[i][l-1]);//如果之前的更小,当然要取之前的。
                ans+=len[i][l];
            }
            for(int l=lmax[i][j];l<=52;l++)
                len[i][l]=0;//因为i,j这个点最大延伸到j-lmax+1。所以这之后的点和j形成的区间,往上只能是0
        }
    }
    return ans;
}
 
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%s",mp[i]+1);
    printf("%lld\n",solve());
 
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值