2022.9.26
不会写就算了,结果题解只有一份代码,所以在观摩了别人的代码后,决定给各位撑把伞,第一次写题解见谅。
一.如何快速比较两个正方形矩阵是不是相同。
把字符转化数字求解,定义base1,base2为基数3,7; has[i][j] = has[i][j-1]*base1 + mp[i][j] - 'a';
has[i][j] = has[i-1][j]*base2 + has[i][j];
这个时候has[i][j]转化过来的数字就是0.0到i.j这个矩阵的特征值k。
has[i][j]通过某种运算与has[i-x][j-x],就可以得到(i-x,j-x)到(i,j)这个小矩阵的特征值k,如果k1=k2,则这两个小矩阵相同。
**补充(这里通过map存储了k的出现次数当k1=k2则k对应的键值对>=2说明找到了答案,如果不熟悉map可以去了解一下。)
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];具体见代码理解,与base1,base2的乘法相关。
二.二分查找 正方形的边长最大才500,(l=0,r=600)不断求mid=(r+l)/2,如果找到了mid成立就找更大的mid,没找到就继续找最大的mid。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const ll base1=3,base2=7;
ll p1[505],p2[505];
ll has[505][505];
char mp[505][505];
map<ll,int>mmp;
int n,m;
void init(){
p1[0]=1;
p2[0]=1;
for(int i=1;i<=505;i++)
{
p1[i]=p1[i-1]*base1;
p2[i]=p2[i-1]*base2;
}
//为后面运算k做准备。
}
void hash1(){
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 mid){
mmp.clear();
for(int i=mid;i<=n;i++)
{
for(int j=mid;j<=m;j++)
{
//求小矩阵的特征值。
ll k=(has[i][j] - has[i-mid][j]*p2[mid] - has[i][j-mid]*p1[mid] + has[i-mid][j-mid]*p1[mid]*p2[mid]);
mmp[k]++;
//当特征值k出现两次说明有两个矩阵相同。
if(mmp[k] >= 2)
return true;
}
}
return false;
} int main(){
int i,j,k,x,y,ans=0;
cin>>n>>m;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cin>>mp[i][j];
}
}
init();
hash1();
/*for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cout<<has[i][j]<<" ";
}
cout<<endl;
}*/
//如果出现错误可以检查has,p1,p2,mid的变化。
int l=0,r=600,mid=0,t=0;
while(l<=r)
{
mid=(l+r)/2;
if(check(mid))
{
//二分查找。
l = mid+1;
ans = mid;
}
else
r=mid-1;
}
cout<<ans<<endl;
}