题干:
给出一个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<cstdio>
//#include<iostream>
//#include<algorithm>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<string>
//#include<cmath>
//#include<cstring>
//using namespace std;
//typedef unsigned long long ull;
//typedef pair<int,int>P;
//#define maxn 505
//int n,m;
//char s[maxn][maxn];
//ull h[maxn][maxn],b[maxn*maxn],base=10007,hhh[maxn][maxn];
//inline int ID(int i,int j) {
// return (i-1)*m+j;
//}
//inline bool check(int mid) {
// map<ull,int>M;
// for(int x=1; x<=n-mid+1; x++)
// for(int y=1; y<=m-mid+1; y++) {
// int xx=x+mid-1,yy=y+mid-1;
// ull val=(h[xx][yy]-h[xx][y-1]-h[x-1][yy]+h[x-1][y-1])*b[(n-x)*m+m-y];
// if(M.find(val)!=M.end())return 1;
// M[val]=1;
// }
// return 0;
//}
//int main() {
// scanf("%d%d",&n,&m);
// for(int i=1; i<=n; i++)scanf("%s",s[i]+1);
// b[0]=1;
// for(int i=1; i<=n; i++)
// for(int j=1; j<=m; j++) {
// h[i][j]=h[i][j-1]+b[ID(i,j-1)]*(s[i][j]-'a');
// b[ID(i,j)]=b[ID(i,j-1)]*base;
// }for(int j=1; j<=m; j++)for(int i=1; i<=n; i++)h[i][j]+=h[i-1][j];
// int l=0,r=min(n,m),mid,ans=0;
// while(l<=r) {
// mid=(l+r)/2;
// if(check(mid))ans=mid,l=mid+1;
// else r=mid-1;
// }
// printf("%d\n",ans);
// return 0;
//}#include<cstdio>
#include<algorithm>
#define N 510
using namespace std;
typedef unsigned long long ll;
const ll D1=97,D2=131;
int n,m,i,j,l,r,mid,ans,t;
char a[N][N];
ll pow1[N],pow2[N],h[N][N],tmp,Hash[N*N];
bool check(int x) {t=0;for(i=1; i<=n; i++) {for(tmp=0,j=1; j<x; j++) tmp=tmp*D1+a[i][j],h[i][j]=0;for(j=x; j<=m; j++) h[i][j]=tmp=tmp*D1-pow1[x]*a[i][j-x]+a[i][j];}for(t=0,i=x; i<=m; i++) {for(tmp=0,j=1; j<x; j++) tmp=tmp*D2+h[j][i];for(j=x; j<=n; j++) Hash[t++]=tmp=tmp*D2-pow2[x]*h[j-x][i]+h[j][i];} sort(Hash,Hash+t);for(i=1; i<t; i++) {if(Hash[i-1]==Hash[i])return 1;}return 0;
}
int main()
{scanf("%d%d",&n,&m);for(i=1; i<=n; i++) {scanf("%s",a[i]+1);for(j=1; j<=m; j++) {a[i][j]-='a';}}l=1,r=min(n,m);pow1[0]=pow2[0]=1;for(i=1; i<=n; i++) pow1[i]=pow1[i-1]*D1;for(i=1; i<=m; i++) pow2[i]=pow2[i-1]*D2;while(l<=r) {mid=(l+r)>>1;if(check(mid)) l=mid+1,ans=mid;else r=mid-1; }printf("%d",ans);return 0;
}
AC代码3:(还是这种二维Hash看得懂一点)
#include<bits/stdc++.h>
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<ull, int> 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;
}