【题目大意】:给出一个n*m的字符矩阵,求出一个最小的子矩阵,使得其在不断复制后可以形成一个新的矩阵覆盖原矩阵。如下面的sanmple,最小的子矩阵是“AB”,经过复制后形成的矩阵是:ABABAB
Sample Input
2 5 ABABA ABABA
Sample Output
2
【解题思路】:最小子矩阵复制后要覆盖原矩阵,也就是说子矩阵必须包含原来矩阵的所有字母,因此我们只需要求的每一行,每一列的最小重复子串即可,这个求解利用到了kmp算法中next数组的一个性质,详见:博客中poj 2406的解释。 再求出各行列的最小重复子串后,只需对所有行的答案求其最小公倍数和所有列的答案求其最小公倍数就可以得到最终答案了。(*************当所求出的最小公倍数大于其列数(行数)时,将其修改为行(列)的长度~~,当年的blog写着我在此处我WA了n次~!!!!!!)【代码】:#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <cmath> #include <string> #include <cctype> #include <map> #include <iomanip> using namespace std; #define eps 1e-8 #define pi acos(-1.0) #define inf 1<<30 #define pb push_back #define lc(x) (x << 1) #define rc(x) (x << 1 | 1) #define lowbit(x) (x & (-x)) #define ll long long char s[100010][80],pp; int next[100010],n,m,temp,a,b; int gcd(int x,int y){ if (!x||!y) return x>y?x:y; for (int t;t=x%y;x=y,y=t); return y; } int lcm(int x,int y){ int d; d=gcd(x,y); return x*y/d; } int solve_kmp_next_row(int k){ next[0]=0; next[1]=0; for(int i=1; i<m; i++){ temp=next[i-1]; while(temp && s[k][temp]!=s[k][i]) temp = next[temp-1]; if(s[k][temp]==s[k][i]) next[i]=temp+1; else next[i]=0; } return m-next[m-1]; } int solve_kmp_next_column(int k){ next[0]=0; next[1]=0; for(int i=1; i<n; i++){ temp=next[i-1]; while(temp && s[temp][k]!=s[i][k]) temp=next[temp-1]; if(s[temp][k]==s[i][k]) next[i]=temp+1; else next[i]=0; } return n-next[n-1]; } int main(){ scanf("%d%d",&n,&m); for (int i=0; i<n; i++){ for (int j=0; j<m; j++) cin >> s[i][j]; scanf("%c",&pp); } a=solve_kmp_next_row(0); b=solve_kmp_next_column(0); for (int i=1; i<n; i++){ a=lcm(a,solve_kmp_next_row(i)); if (a>=m) { a=m; break; } } for (int i=1; i<m; i++){ b=lcm(b,solve_kmp_next_column(i)); if (b>=n) { b=n; break; } } printf("%d",a*b); return 0; }