牛客多校第七场 J Sudoku Subrectangles (简单题 暴力题)

 真羡慕两题的

 题意 :给你一个n*m的矩阵  由大小写字母构成     先让你找出子矩阵的个数  满足 子矩阵每行的字母都不同  每列的字母都不同 

题解:简单题就简单题吧   反正我没写出来 哼        最暴力的做法 乍一看是  n*n*m  暴力找子矩阵的第一行行 for最后一行的位置,然后对每一列进行判断      因为只有52个字母  那么子矩阵的高度不会超过52  那么复杂度就是 n*25*m  还行吧 反正就是暴力

为什么  每一列的判断只要 m就够了(其实还有常数  问题不大)   因为每多一列 那么出现重复的概率越大  那么如果以这一列为子矩阵右边界  那么左边界只会往右靠 

代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<vector>
using namespace std;
typedef long long ll;
char ss[1005][1005];
int mp[1005][1005];
int nowlf[1005];
ll numcol[1005];
int last[60];
int main()
{
    int n,m;
    ll ans=0;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) scanf("%s",ss[i]);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(ss[i][j]>='a'&&ss[i][j]<='z')
            {
                mp[i][j]=ss[i][j]-'a'+26;
            }
            else
            {
                mp[i][j]=ss[i][j]-'A';
            }
        }
    }
    for(int lx=0;lx<n;lx++)      //上边界
    {
        memset(nowlf,-1,sizeof(nowlf));
        memset(numcol,0,sizeof(numcol));
        for(int rx=lx;rx<n;rx++)  //下边界
        {
            if(rx-lx+1>52) break;
            ll t=1;
            for(int r=0;r<m;r++)
            {
                int x=mp[rx][r];
                if(numcol[r]&(t<<x))  //记录这一列 x有没有出现过  
                {
                    nowlf[r]=r;       //如果出现过 那么以这列的左边界就是自己  算答案时为 r-l  也就是0
                }
                numcol[r]|=t<<x;
            }
            memset(last,-1,sizeof(last));//用于记录这一行中某个字母之前出现的位置
            for(int r=0;r<m;r++)
            {
                nowlf[r]=max(nowlf[r],last[mp[rx][r]]);  //行列同一条件  得到左边界
                last[mp[rx][r]]=r;
            }
            int l=-1;
            for(int r=0;r<m;r++)      
            {
                l=max(l,nowlf[r]);  //左边界只会向右移动
                ans+=r-l;
            }
        }

    }
    printf("%lld\n",ans);

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值