Ural 1486. Equal Squares 字符串hash

1486. Equal Squares

Time limit: 2.0 second
Memory limit: 16 MB
During a discussion of problems at the Petrozavodsk Training Camp, Vova and Sasha argued about who of them could in 300 minutes find a pair of equal squares of the maximal size in a matrix of size N ×  M containing lowercase English letters. Squares could overlap each other but could not coincide. He who had found a pair of greater size won. Petr walked by, looked at the matrix, said that the optimal pair of squares had sides  K, and walked on. Vova and Sasha still cannot find this pair. Can you help them?

Input

The first line contains integers  N and  M separated with a space. 1 ≤  NM ≤ 500. In the next  Nlines there is a matrix consisting of lowercase English letters,  M symbols per line.

Output

In the first line, output the integer  K which Petr said. In the next two lines, give coordinates of upper left corners of maximal equal squares. If there exist more than one pair of equal squares of size  K, than you may output any of them. The upper left cell of the matrix has coordinates (1, 1), and the lower right cell has coordinates ( NM). If there are no equal squares in the matrix, then output 0.

Sample

input output
5 10
ljkfghdfas
isdfjksiye
pgljkijlgp
eyisdafdsi
lnpglkfkjl
3
1 1
3 3
Problem Author: Vladimir Yakovlev
Problem Source: The XIth USU Programing Championship, October 7, 2006
题意:一个n*m的矩阵,求此矩阵中最大的完全相同的2个正方形。
论文例题:《Hash在信息学竞赛中的一类应用 http://www.doc88.com/p-167100142515.html
二分查找正方形的边长,然后使用一个Hash表来判断该边长是否可行。

多维的KMP要从1维的情况开始考虑,并推广至高维。那么这种计算Hash函数的匹配算法我们也可以先考虑一维的情况——就是Rabin-Karp算法。

对于一个字符串S,可以使用这个函数求出其Hash值:


那么,模式串Y的Hash值就可以轻松地求出。记待匹配串X从第i个字符开始的长度为M的子串为Si,则不难发现f(Si+1)和f(Si)的关系:


换个角度,如果不考虑mod q,这个函数就是把字符串看作一个p进制数求出的值,这样,Xi+1就是Xi “左移”一位,然后去掉最前面一位,再加上右面新进来的一位得到的。因此上面的递推公式也是显然的。

#include<stdio.h>
#include<cstring>
#include<cstdlib>
#define Min(a,b) (a<b?a:b)
struct node
{
    int x,y;
} hash[250008],a1,a2;
int  p=4877;
int n,m,f[505][505],ans,x1,x2,y1,y2,a[505][505],g[505][505],b[250008],next[250008],start[530000],tot;
long long s[505];

void  insert(int x,node t)//将HASH值x插入链表
{
    hash[++tot]=t;
    next[tot]=start[x];
    start[x]=tot;
}

bool  cmp(int x,int l)//比较HASH值为X的相同矩阵是否出现过
{
    int i,j;
    for  (int g=start[x]; g; g=next[g])
    {
        a2=hash[g];
        j=l;
        for  (i=0; i<l&&j>=l; i++)
            if  (f[a1.x][a1.y-i]!=f[a2.x][a2.y-i]) break;
        if  (i>=l)
        {
            if  (l>ans) ans=l,x1=a1.x,y1=a1.y,x2=a2.x,y2=a2.y;
            return true;
        }
    }
    return false;
}

int  main()
{
    int i,j,k,l,r;
    char c;
    scanf("%d%d%*c",&n,&m);
    for  (i=1; i<=n; i++)
    {
        for  (j=1; j<=m; j++)
        {
            scanf("%c",&a[i][j]);
            a[i][j]-=97;
        }
        scanf("%*c");
    }
    s[0]=1;
    for  (i=1; i<=n; i++) s[i]=(p*s[i-1])&524287;

    r=Min(n,m);
    l=1;
    while  (l<=r)
    {
        k=l+r>>1;
        for  (i=1; i<=n; i++)
            for  (j=1; j<=m; j++)
            {
                if  (i<k) f[i][j]=f[i-1][j]*p+a[i][j]&524287;
                else  f[i][j]=((f[i-1][j]-a[i-k][j]*s[k-1]&524287)+524288&524287)*p+a[i][j]&524287;//减去最高位,加上最低位

            }//f[i][j]存下第j列第i行往上长度为k的串的HASH值
        memset(start,0,sizeof(start));
        tot=0;
        for  (j=1; j<=m&&i>n; j++)
            for  (i=k; i<=n; i++)
            {
                if  (j<k) g[i][j]=g[i][j-1]*p+f[i][j]&524287;
                else
                {
                    g[i][j]=((g[i][j-1]-f[i][j-k]*s[k-1]&524287)+524288&524287)*p+f[i][j]&524287;
                    if  (cmp(g[a1.x=i][a1.y=j],k))   break;
                    insert(g[i][j],a1);
                }
            }//g[i][j]存下右下角为第i行第j列长度为k的矩阵的HASH值
        if  (j<=m) l=k+1;
        else r=k-1;

    }
    if  (ans)  printf("%d\n%d %d\n%d %d\n",ans,x1-ans+1,y1-ans+1,x2-ans+1,y2-ans+1);
    else  printf("0\n");
    return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值