真羡慕两题的
题意 :给你一个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;
}