1.题目描述:点击打开链接
2.解题思路:本题可以利用AC自动机解决,但是发现,这种方法时间效率比较低,个人推荐利用二维Hash来解决本题。经过OJ上测试,AC自动机的方法需要1s以上,而二维Hash只需要不到100ms!因此下面介绍如何用二维hash来解决本题。
首先,任何hash技术都需要给定一个函数,使得不同字符串经过计算得到的hash值产生的冲突越少越好。对于字符矩阵,我们一般利用二维hash来处理。虽然是二维,但原理和一维的类似,即首先把每一行的前j个字符进行一维hash,对前i行进行处理,得到i行1列的hash值,接下来对这i行1列hash值再次hash,最终得到的hash值就是(i,j)处的hash值。写成递推式如下:
上式中,每一行进行hash时候,seed=q;每一列进行hash的时候,seed=p,下面举一个简单的例子来说明此方法。
假设现在的字符矩阵如下:
对该矩阵按照上述公式计算每一格的hash值,可以得到下面的hash矩阵:
通过观察不难发现,二维hash的确就是2个一维hash的复合过程。而且,如果p,q选择合适,可以保证(i,j)处的hash值就可以看做子矩阵(0,0)~(i,j)的hash值,而且只要子矩阵不相同,那么对应的hash值一定不同。下面我们就用矩阵右下角的hash值代表整个矩阵的hash值。
那么,如何从该矩阵中计算(i,j)~(i+x-1,j+y-1)这个子矩阵的hash值呢?还是利用最初的计算公式,只需要反复迭代使用,即可得到下述公式:
这样,有了上述的分析,本题就不难解决了,首先计算出原始字符矩阵的hash矩阵,同时算出输入的P矩阵的hash值h,通过枚举x*y的子矩阵,并计算该子矩阵的hash值是否等于h,如果是,则ans++。最终即可得到答案。
本题的时间复杂度是O((N-x)*(M-y))。
3.代码:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
//typedef pair <int, int> P;
const int N=1101;
const int p=131;
const int q=1331;
ll Hash[N][N];
ll hv[110][110];
ll powp[N],powq[N];
char str[N];
void init()//初始化p^i,q^i的结果
{
powp[0]=powq[0]=1;
for(int i=1;i<N;i++)
{
powp[i]=powp[i-1]*p;
powq[i]=powq[i-1]*q;
}
}
int main()
{
int T;
scanf("%d",&T);
init();
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
me(Hash);me(hv);
for(int i=1;i<=n;i++)
{
scanf("%s",str+1);
for(int j=1;j<=m;j++)
Hash[i][j]=Hash[i-1][j]*p+Hash[i][j-1]*q-Hash[i-1][j-1]*p*q+str[j];//计算Hash矩阵
}
int x,y;
scanf("%d%d",&x,&y);
for(int i=1;i<=x;i++)
{
scanf("%s",str+1);
for(int j=1;j<=y;j++)
hv[i][j]=hv[i-1][j]*p+hv[i][j-1]*q-hv[i-1][j-1]*p*q+str[j];//计算P矩阵的hash值
}
ll h;
int ans=0;
for(int i=1;i<=n-x+1;i++)
for(int j=1;j<=m-y+1;j++)//枚举x*y的子矩阵
{
h=Hash[i+x-1][j+y-1]-Hash[i-1][j+y-1]*powp[x]-Hash[i+x-1][j-1]*powq[y]+Hash[i-1][j-1]*powp[x]*powq[y];
if(h==hv[x][y])ans++; //相等,则ans++
}
printf("%d\n",ans);
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u014800748/article/details/48055941