题目大意
给一个n*m的字符矩阵,求有多少个不同的子矩阵,字符集为大写英文字母。
n,m<=110
分析
先往哈希上面想想,直接暴力搞每一个矩阵的哈希值再判重是
n6
,然后就开始优化。首先确定宽度,行数就可以递增地继承信息。而宽度的递增,也是可以继承的,最后就可以
n4
。
实际上,我们确定宽度width以后,就可以转化为新矩阵,其中每一个元素都是原矩阵1*width的子矩阵。这样我们只用统计整个矩阵里,k*1的不同子矩阵个数。把它们打横来看,就是数个字符串了。用特殊字符#把数个字符串连接起来,问题变成求整个字符串里,不包含#的不同子串有多少个。
SA或者SAM解决了。
写题
智商捉急啊···一开始用特殊的哈希技巧来打70分,结果哈希太烂,小数据都会有误。
改题的时候,SA好久不打了,还得看模板,所以改题效率特别低。正确的姿势是回忆好SA,再开始打。然而我边打边看,不能专一做事,脑子一片混乱,调试也不高效。这是值得注意的地方。
还有一点,字符串哈希最好用多个质数模数。
贴个代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
typedef long long ll;
const int N=115,N2=24205,mo=1000000007,mo1=128473;
char ch;
int f[N][N],g[N][N],sa[N2],height[N2],x[N2],x1[N2],y[N2],wv[N2],ws[N2],n,m,i,j,k,l,a[N][N],res,rank[N2],tt,t1,p,pos,dur,ans,width;
struct rec
{
int val,pos,val1;
}b[N2];
bool cmp(rec a,rec b)
{
return a.val<b.val;
}
void getsa()
{
fo(i,1,tt) wv[i]=0;
fo(i,1,tt) wv[x[i]]++;
fo(i,1,tt) wv[i]+=wv[i-1];
fd(i,tt,1)
{
sa[wv[x[i]]]=i;
wv[x[i]]--;
}
j=1;
while (j<=tt)
{
p=0;
fo(i,tt-j+1,tt) y[++p]=i;
fo(i,1,tt)
if (sa[i]>j)
y[++p]=sa[i]-j;
fo(i,1,tt) wv[i]=0;
fo(i,1,tt) ws[i]=x[y[i]];
fo(i,1,tt) wv[ws[i]]++;
fo(i,1,tt) wv[i]+=wv[i-1];
fd(i,tt,1)
{
sa[wv[ws[i]]]=y[i];
wv[ws[i]]--;
}
p=1;
fo(i,1,tt) y[i]=x[i];
x[sa[1]]=1;
fo(i,2,tt)
{
if (y[sa[i]]!=y[sa[i-1]]||y[sa[i]+j]!=y[sa[i-1]+j])
p++;
x[sa[i]]=p;
}
j*=2;
}
}
void getheight()
{
fo(i,1,tt) rank[sa[i]]=i;
k=0;
fo(i,1,tt)
{
if (k) k--;
j=sa[rank[i]-1];
while (j+k<=tt&&i+k<=tt&&x1[j+k]==x1[i+k]) k++;
height[rank[i]]=k;
}
}
void getans()
{
fo(i,1,tt)
{
pos=sa[i];
dur=((sa[i]-1)/(n+1)+1)*(n+1)-pos;
ans+=max(dur-height[i],0);
}
}
int main()
{
freopen("matrix.in","r",stdin);
// freopen("matrix.out","w",stdout);
scanf("%d%d\n",&n,&m);
fo(i,1,n)
{
fo(j,1,m)
{
scanf("%c",&ch);
a[i][j]=ch;
}
scanf("\n");
}
fo(width,1,m)
{
tt=0;
res=m-width+1;
fo(i,1,n) fo(j,1,res)
{
g[i][j]=0;
f[i][j]=(ll)(f[i][j]*13531+a[i][j+width-1])%mo;
b[++tt].val=f[i][j];
b[tt].pos=i*m+j-1;
}
sort(b+1,b+1+tt,cmp);
b[0].val=-1;
t1=0;
fo(i,1,tt)
{
if (b[i].val!=b[i-1].val) t1++;
g[b[i].pos/m][b[i].pos%m+1]=t1;
}
tt=0;
fo(j,1,res)
{
fo(i,1,n)
x[++tt]=g[i][j];
x[++tt]=t1+1;
}
fo(i,1,tt) x1[i]=x[i];
getsa();
getheight();
getans();
fo(i,1,tt+4) y[i]=wv[i]=ws[i]=sa[i]=rank[i]=height[i]=x[i]=x1[i]=0;
}
printf("%d",ans);
}