题干:
给出一个n * m的矩阵。让你从中发现一个最大的正方形。使得这样子的正方形在矩阵中出现了至少两次。输出最大正方形的边长。
第一行两个整数n, m代表矩阵的长和宽;
接下来n行,每行m个字符(小写字母),表示矩阵;
输出一个整数表示满足条件的最大正方形的边长。
示例1
复制
5 10
ljkfghdfas
isdfjksiye
pgljkijlgp
eyisdafdsi
lnpglkfkjl
复制
3
对于30%的数据,n,m≤100;
对于100%的数据,n,m≤500;
解题报告:
非常恶心的字符串Hash,,琢磨了半天才看明白、、这种前缀的是需要去模数的
AC代码:
//#include
//#include
//#include
//#include
//#include
AC代码3:(还是这种二维Hash看得懂一点)
#include
using namespace std;
typedef unsigned long long ull;
const int maxn=2e6+10;
const ull base1=131,base2=233; //base,基数
int n, m;
char mp[510][510];
ull has[510][510];
ull p1[510], p2[510];
map mmp;
void init()
{
p1[0] = p2[0] = 1;
for(int i = 1; i <= 505; i ++)
{
p1[i] = p1[i-1]*base1;
p2[i] = p2[i-1]*base2;
}
}
void Hash()
{
has[0][0] = 0;
has[0][1] = 0;
has[1][0] = 0;
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
{
has[i][j] = has[i][j-1]*base1 + mp[i][j] - 'a';
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j ++)
{
has[i][j] = has[i-1][j]*base2 + has[i][j];
}
}
}
bool check(int x)
{
mmp.clear();
for(int i = x; i <= n; i ++)
{
for(int j = x; j <= m; j ++)
{
ull k = has[i][j] - has[i-x][j]*p2[x] - has[i][j-x]*p1[x] + has[i-x][j-x]*p1[x]*p2[x];
mmp[k] ++;
if(mmp[k] >= 2)
return true;
}
}
return false;
}
int main()
{
init();
while(~scanf("%d%d", &n, &m))
{
for(int i = 1; i <= n; i ++)
{
scanf("%s", mp[i]+1);
}
Hash();
int l = 0, r = 600, ans = 0;
while(l <= r)
{
int mid = (l+r)/2;
if(check(mid))
{
l = mid+1;
ans = mid;
}
else
{
r = mid-1;
}
}
printf("%d\n", ans);
}
return 0;
}