给一个字符矩阵,求一个最小的矩阵,使得这个矩阵复制若干次可以完整包含原矩阵。首先考虑行,找出每行的最小重复单元的长度后,他们的最小公倍数就是横向上的最小单元长度;同理纵向上求出纵向上的最小单元长度,要注意的一点是如果这两个长度大于n或m得话,就取n或m,因为最长也就是他们本身的长度..那么现在的问题就是求一行(或一列)的最小重复单元了,求出该行的失配函数,len-f[len]就是这一行的最小重复单元的长度,举个例子
12345678
12345678
如果f[8]=3,显然后345678=123456,而下面的78又等于上面的78,因此等于下面的56,一次类推就会得到12=34=56=78,也就是整个串是由12重复否成的。理解了这点,剩下的就是对每行求一下重复单元的长度,最后组合一下最小公倍数,对每列做同样的操作,最后ansx*ansy就是答案。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <map>
#include <string>
#include <cstring>
#include <string>
using namespace std;
typedef long long ll;
const int maxn=10020;
char mat[10020][100];
char str[maxn],s[maxn],s1[maxn];
int f[maxn];
void getFail(char* P,int* f)
{
int m=strlen(P);
f[0]=0;
f[1]=0;
for (int i=1; i<m; i++)
{
int j=f[i];
while(j && P[i]!=P[j]) j=f[j];
f[i+1]=P[i]==P[j]?j+1:0;
}
}
int find(char* T,char* P,int* f)
{
int n=strlen(T);
int m=strlen(P);
getFail(P,f);
int j=0;
for (int i=0; i<n; i++)
{
while(j && P[j]!=T[i]) j=f[j];
if (P[j]==T[i]) j++;
if (j==m) return i-m+1;
}
}
ll gcd(ll x,ll y)
{
if (y==0) return x;
return gcd(y,x%y);
}
ll lcs(ll x,ll y)
{
return x*y/gcd(x,y);
}
int n,m,k;
int main()
{
// freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
for (int i=0; i<n; i++)
scanf("%s",mat[i]);
strcpy(s,mat[0]);
getFail(s,f);
ll ans=strlen(s)-f[strlen(s)];
ll x;
for (int i=1; i<n; i++)
{
strcpy(s,mat[i]);
getFail(s,f);
x=strlen(s)-f[strlen(s)];
ans=lcs(ans,x);
}
if (ans>m) ans=m;
ll ans1;
for (int j=0; j<n; j++)
s[j]=mat[j][0];
s[n]='\0';
getFail(s,f);
ans1=strlen(s)-f[strlen(s)];
for (int i=1; i<m; i++)
{
for (int j=0; j<n; j++)
s[j]=mat[j][i];
s[n]='\0';
getFail(s,f);
x=strlen(s)-f[strlen(s)];
ans1=lcs(ans1,x);
}
if (ans1>n) ans1=n;
printf("%lld\n",ans*ans1);
}
return 0;
}