题意:
n*m矩阵,求多少个每行每列都没有重复字母(分大小写)的矩阵
解析:
对每一个位置记录下最高往上可以走多少,往左可以走多少,然后遍历每一列,维护一个从当前位置往左走的每个位置的上限的单调栈
代码:
#include<bits/stdc++.h>
using namespace std;
char M[1002][1002];int n,m;
long long ans=0;
int l[1002][1002];
int uu[1002][1002];
int vis[200];
int sta[100];
void init(){
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
for(int j=1;j<=m;j++){
l[i][j]=min(l[i][j-1]+1,j-vis[M[i][j]]);
vis[M[i][j]]=j;
}
}
for(int j=1;j<=m;j++){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
uu[i][j]=min(uu[i-1][j]+1,i-vis[M[i][j]]);
vis[M[i][j]]=i;
}
}
for(int j=1;j<=m;j++){//遍历每一列
//每一列的遍历中公用与维护sta
memset(sta,0,sizeof(sta));
for(int i=1;i<=n;i++){
for(int k=0;k<l[i][j];k++){
int p=j-k;
sta[k]=min(sta[k]+1,uu[i][p]);//得到这一个位置的往上走的上限
if(k)sta[k]=min(sta[k],sta[k-1]);//和之前的sta比较
ans+=(long long)sta[k];
}
for(int k=l[i][j];k<=54;k++)sta[k]=0;//这部分清0限制下个i的sta[k]
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%s",M[i]+1);
init();
cout<<ans<<endl;
}