poj2185 Milking Grid 二维kmp

     给一个字符矩阵,求一个最小的矩阵,使得这个矩阵复制若干次可以完整包含原矩阵。首先考虑行,找出每行的最小重复单元的长度后,他们的最小公倍数就是横向上的最小单元长度;同理纵向上求出纵向上的最小单元长度,要注意的一点是如果这两个长度大于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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值