jzoj 4683. 【GDOI2017模拟8.11】矩阵 后缀数组+哈希表

来源:互联网 发布:apache 安装 编辑:程序博客网 时间:2024/04/19 11:49

题意:求一个矩阵中有多少不同的子矩阵


分析:枚举宽度 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 longusing 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;}




0 0
原创粉丝点击