题意:求一个矩阵中有多少不同的子矩阵
分析:枚举宽度 w,hash[i][j]表示,表示第 i 行,从第 j 个字符开始的 w 个字符的哈希值。然后把起点相同的列,连在一起,也就是竖着把每一列连在一起,列与列之间用一个特殊字符隔开,变成了一个串剩下的就是求这个串有多少个不同的子串。用后缀数组来求子串种数。
时间复杂度: O(n^3log^2n)
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define N 120 #define MOD1 2477 #define MOD2 2969 #define ll long long using namespace std; int n,m,s[N*N],b[MOD1*MOD2],c[N*N],d[N*N],sa[N*N],rank[N*N],height[N*N],l[N*N],hash[N][N],hash1[N][N],hash2[N][N]; int v[MOD1][MOD2],cnt; char c1[N],ch[N][N]; void getsa(int n,int m) { for (int i=0;i<=m;i++) b[i]=0; for (int i=1;i<=n;i++) b[s[i]]++; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) c[b[s[i]]--]=i; int t=0; for (int i=1;i<=n;i++) { if (s[c[i]]!=s[c[i-1]]) t++; rank[c[i]]=t; } int j=1; while (j<=n) { for (int i=0;i<=n;i++) b[i]=0; for (int i=1;i<=n;i++) b[rank[i+j]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) c[b[rank[i+j]]--]=i; for (int i=0;i<=n;i++) b[i]=0; for (int i=1;i<=n;i++) b[rank[i]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) d[b[rank[c[i]]]--]=c[i]; int t=0; for (int i=1;i<=n;i++) { if (rank[d[i]]!=rank[d[i-1]]||rank[d[i]]==rank[d[i-1]]&&rank[d[i]+j]!=rank[d[i-1]+j]) t++; c[d[i]]=t; } for (int i=1;i<=n;i++) rank[i]=c[i]; if (t==n) break; j*=2; } for (int i=1;i<=n;i++) sa[rank[i]]=i; } void getheight(int n) { int k=0; for (int i=1;i<=n;i++) { if (k) k--; int j=sa[rank[i]-1]; while (i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) k++; height[rank[i]]=k; } } int getans(int n) { int ans=0; for (int i=1;i<=n;i++) ans+=l[sa[i]]-height[i]; return ans; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%s",c1); for (int j=1;j<=m;j++) ch[i][j]=c1[j-1]; } int ans=0; for (int w=1;w<=m;w++) { for (int i=1;i<=n;i++) for (int j=1;j<=m-w+1;j++) { hash1[i][j]=(hash[i][j]*26+ch[i][j+w-1]-'A')%MOD1; hash2[i][j]=(hash[i][j]*26+ch[i][j+w-1]-'A')%MOD2; int x=hash1[i][j],y=hash2[i][j]; if (!v[x][y]) v[x][y]=++cnt; hash[i][j]=v[x][y]; } int len=0,hehe=cnt; for (int j=1;j<=m-w+1;j++) { if (j>1) { s[++len]=++hehe; l[len]=0; } for (int i=1;i<=n;i++) { s[++len]=hash[i][j]; l[len]=n-i+1; } } memset(rank,0,sizeof(rank)); getsa(len,hehe); getheight(len); ans+=getans(len); } printf("%d",ans); return 0; }