AcWing159. 奶牛矩阵
每天早上,农夫约翰的奶牛们被挤奶的时候,都会站成一个 R 行 C 列的方阵。
现在在每个奶牛的身上标注表示其品种的大写字母,则所有奶牛共同构成了一个 R 行 C 列的字符矩阵。
现在给定由所有奶牛构成的矩阵,求它的最小覆盖子矩阵的面积是多少。
如果一个子矩阵无限复制扩张之后得到的矩阵能包含原来的矩阵,则称该子矩阵为覆盖子矩阵。
输入格式
第 1 行:输入两个用空格隔开的整数,R 和C。
第 2..R+1 行:描绘由奶牛构成的 R 行 C 列的矩阵,每行 C 个字符,字符之间没有空格。
输出格式
输出最小覆盖子矩阵的面积。(每个字符的面积为 1)
数据范围
1≤R≤10000,
1≤C≤75
输入样例:
2 5
ABABA
ABABA
输出样例:
2
提示
样例中给出的矩阵的最小覆盖子矩阵为 AB,面积为 2。
思路:行列独立,采用降维处理,那么可以把r行压缩成一行,组成一维,再用字符串hash,再求出最小循环节ans1=n-ne[n]
同样也可以对列这样处理,求出ans2,这样求出的两个子矩阵长度的乘积ans1*ans2就是答案。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define M 13331//常用131,13331
#define N 15000
char s[N][100];
int ne[N];
ull f[N],p[N];
int kmp(int n){//kmp算法
for(int i=2,j=0;i<=n;i++){
while(j>0&&f[i]!=f[j+1]) j=ne[j];
if(f[i]==f[j+1]) j++;
ne[i]=j;
}
return n-ne[n];//最循环节长度=字符串长度n-next[字符串长度n]
int main(){
int r,c,ans=0;
p[0]=1;
for(int i=1;i<=N;i++) p[i]=p[i-1]*M;
scanf("%d%d",&r,&c);
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
cin>>s[i][j];
}
}
//压缩列
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
f[i]=f[i]*M+s[i][j];
}
}
ans=kmp(r);
memset(f,0,sizeof(f));//记住清0
//压缩行
for(int i=1;i<=c;i++){
for(int j=1;j<=r;j++){
f[i]=f[i]*M+s[j][i];
}
}
ans*=kmp(c);
printf("%d",ans);
return 0;
}