1486. Equal Squares
Time limit: 2.0 second
Memory limit: 16 MB
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 ≤
N,
M ≤ 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 (
N,
M). 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
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;
}