枚举子矩阵的宽度
不同宽度的子矩阵一定本质不同,相同宽度的子矩阵有 n2 n 2 个,把每个宽度为 k k <script type="math/tex" id="MathJax-Element-4">k</script> 的子矩阵每一行hash一下,就变成了一个字符串,求本质不同的个矩阵用广义后缀自动机就行了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
typedef unsigned long long ull;
const int N=120,base=29,M=N*N*2;
map<ull,int> nxt[M];
ull hs[N][N],pw[N];
int n,m,cnt,p,len[M],fail[M];
char a[N][N];
inline ull Getsub(int i,int l,int r){
return hs[i][r]-hs[i][l-1]*pw[r-l+1];
}
void extend(ull c){
int np=++cnt; len[np]=len[p]+1;
while(p && !nxt[p].count(c)) nxt[p][c]=np,p=fail[p];
if(!p) fail[np]=1;
else{
int q=nxt[p][c];
if(len[q]==len[p]+1) fail[np]=q;
else{
int nq=++cnt; len[nq]=len[p]+1;
nxt[nq]=nxt[q];
fail[nq]=fail[q];
fail[q]=fail[np]=nq;
while(p && nxt[p].count(c) && nxt[p][c]==q) nxt[p][c]=nq,p=fail[p];
}
}
p=np;
}
int ans;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",a[i]+1);
pw[0]=1; for(int i=1;i<=m;i++) pw[i]=pw[i-1]*base;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
hs[i][j]=hs[i][j-1]*base+a[i][j]-'A'+1;
for(int k=1;k<=m;k++){
for(int i=1;i<=cnt;i++) nxt[i].clear();
cnt=1;
for(int i=1;i+k-1<=m;i++){
p=1;
for(int j=1;j<=n;j++) extend(Getsub(j,i,i+k-1));
}
for(int i=2;i<=cnt;i++) ans+=len[i]-len[fail[i]];
}
printf("%d\n",ans);
return 0;
}