题意:
给出一个n行m列的矩阵,要求求出最小子矩阵使得子矩阵重复所得的矩阵可以覆盖当前矩阵…
分析:
最小的子矩阵一定是前缀…
如果这个问题是一维的怎么办…求出nxt数组,ans=m-nxt[m]…
那么现在变为二维了…我们看m只有75,但是n有10000,这显然是让我们把行看成一个字符,O(n)的求出列的一维ans,所以我们暴力求出min(len[i])(1<=i<=n)最小的所有行都满足的重复子串长度…然后求转化为一维的了…
代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=10000+5,maxm=75+5;
int n,m,nxt[maxn],ans,cnt[maxm];
char mp[maxn][maxm];
inline bool check(int x,int y,int lenth){
for(int i=1;i<=lenth;i++)
if(mp[x][i]!=mp[y][i])
return false;
return true;
}
inline void getnext(int lenth){
int k;
nxt[0]=nxt[1]=0;
for(int i=1;i<n;i++){
k=nxt[i];
while(k&&!check(k+1,i+1,lenth))
k=nxt[k];
if(check(k+1,i+1,lenth))
nxt[i+1]=k+1;
else
nxt[i+1]=0;
}
}
inline bool check2(int id,int lenth){
for(int i=1,j=1;j<=m;i++,j++){
if(i==lenth+1)
i=1;
if(mp[id][i]!=mp[id][j])
return false;
}
return true;
}
signed main(void){
scanf("%d%d",&n,&m);ans=n*m;
for(int i=1;i<=n;i++)
scanf("%s",mp[i]+1);
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(check2(i,j))
cnt[j]++;
int x;
for(x=1;x<m;x++)
if(cnt[x]==n)
break;
getnext(x);
cout<<(n-nxt[n])*x<<endl;
return 0;
}
by >_< NeighThorn