题意:
给你一个nm的字符矩阵,一个mn的字符矩阵,问你他们相同的m*m的字符矩阵所在第一个矩阵的行数和第二个矩阵的列数。
题解:
我们把第一个字符矩阵当成一行处理,然后对于第二个字符矩阵,我们预处理所有的mm块将哈希值保存到左上角,如图:
注意要用双哈希,但是脸黑也可能过不去。。
之后我们就枚举第一个字符矩阵的起始位置,再枚举第二个字符矩阵的起始位置即可,时间复杂度nn,但是预处理时间复杂度nmm,也有更优的预处理方法,但没必要
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pa pair<ll,ll>
const ll mod=1e9+7,p1=37,p2=23;
char s1[400005],s2[205][2005];
ll sump1[400005],sump2[400005];
pa hash2[2005],hash1[400005];
pa gethash1(int sta,int fin)
{
ll h1=(hash1[fin].first-hash1[sta].first*sump1[fin-sta]%mod+mod)%mod;
ll h2=(hash1[fin].second-hash1[sta].second*sump2[fin-sta]%mod+mod)%mod;
return (pa){h1,h2};
}
int n,m;
void Hash()
{
ll ret1,ret2;
sump1[0]=sump2[0]=1;
for(int i=1;i<=n*m;i++)
{
hash1[i].first=(hash1[i-1].first*p1+(ll)s1[i])%mod;
hash1[i].second=(hash1[i-1].second*p2+(ll)s1[i])%mod;
sump1[i]=sump1[i-1]*p1%mod,sump2[i]=sump2[i-1]*p2%mod;
}
for(int i=1;i<=n-m+1;i++)
{
ret1=ret2=0;
for(int j=1;j<=m;j++)
{
for(int k=i;k<=m+i-1;k++)
{
ret1=(ret1*p1+(ll)s2[j][k])%mod;
ret2=(ret2*p2+(ll)s2[j][k])%mod;
}
}
hash2[i]=(pa){ret1,ret2};
}
}
int main()
{
scanf("%d%d",&n,&m);
getchar();
for(int i=1;i<=n*m;i++)
{
scanf("%c",s1+i);
if(i%m==0)
getchar();
}
for(int i=1;i<=m;i++)
scanf("%s",s2[i]+1);
Hash();
//if(n==2000&&m==1)
//printf("%s",s2[1]);
for(int i=1;i<=n*m-m*m+1;i+=m)
{
pa h1=gethash1(i-1,i+m*m-1);
for(int j=1;j<=n-m+1;j++)
if(h1==hash2[j])
return 0*printf("%d %d\n",(i+m-1)/m,j);
}
}