矩阵

题目

题目

思路

怎么可能是Hash

结果就是Hash,亏我想了一下午的数据结构(╯‵□′)╯︵┻━┻。

首先,这道题目是二维Hash,我们讲讲二维Hash,仍然是那个参数\(a\),对于一个矩阵,,行的处理:\(P(i,j)=P(i,j-1)*a+v(i,j)\),而列呢则是:\(P(i,1)=P(i-1,m)*a+v(i,1)\),所以对于\(i\)行\(j\)列的数,它参数\(a\)的指数是\((n-i)*m+(m-j+1)\)。

注:代码中的模数直接采用unsigned long long 的自然溢出来处理。

那么如何在\(O(nm)\)的时间预处理并且在\(O(1)\)的时间内计算出子矩阵的Hash呢?

预处理我就不说了,但这个\(O(1)\)真的挺有意思的,我们不难发现,上下两行的指数差是\(m\),左右列是\(1\),我们可以利用这个性质像一维那样用容斥原理暴力搞,不过要分成四个部分罢了。

最后我们把母矩阵中所有大小为\(A*B\)的矩阵的Hash全部塞进数组里面,二分查找,此题完结。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define  N  1100
#define  M  1100000
using  namespace  std;
typedef  unsigned  long  long  LL;
int  a[N][N],b[N][N];
LL  ha[N][N],hb[N][N];
LL  pl=3,list[M],top,p[M];
int  n,m,A,B,Q;
char  st[N];
bool  check(LL  x)
{
	int  l=1,r=top,ans=0;
	while(l<=r)
	{
		int  mid=(l+r)/2;
		if(list[mid]<=x)ans=mid,l=mid+1;
		else  r=mid-1;
	}
	if(list[ans]==x)return  1;
	return  0;
}
int  main()
{
//	freopen("matrix4.in","r",stdin);
//	freopen("juruo.out","w",stdout); 
	scanf("%d%d%d%d",&n,&m,&A,&B);
	int  nm=n*m;
	p[0]=1;
	for(int  i=1;i<=nm;i++)
	{
		p[i]=p[i-1]*pl;
	}
	for(int  i=1;i<=n;i++)
	{
		scanf("%s",st+1);
		for(int  j=1;j<=m;j++)a[i][j]=st[j]-'0';
	}
	scanf("%d",&Q);
	for(int  i=1;i<=n;i++)
	{
		for(int  j=1;j<=m;j++)ha[i][j]=ha[i][j-1]*pl+a[i][j];
	}
	for(int  i=1;i<=n;i++)
	{
		for(int  j=1;j<=m;j++)
		{
			ha[i][j]=ha[i-1][j]*p[m]+ha[i][j];
			if(i>=A  &&  j>=B)
			{
				int  x=i-A,y=j-B;
				list[++top]=(ha[i][j]-ha[x][j]*p[A*m])-(ha[i][y]-ha[x][y]*p[A*m])*p[B];//计算子矩阵的Hash
			}
		}
	}
	sort(list+1,list+top+1);
	for(int  t=1;t<=Q;t++)
	{
		for(int  i=1;i<=A;i++)
		{
			scanf("%s",st+1);
			for(int  j=1;j<=B;j++)b[i][j]=st[j]-'0';
		}
		for(int  i=1;i<=A;i++)
		{
			for(int  j=1;j<=B;j++)hb[i][j]=hb[i][j-1]*pl+b[i][j];
		}
		for(int  i=1;i<=A;i++)
		{
			for(int  j=1;j<=B;j++)hb[i][j]=hb[i-1][j]*p[m]+hb[i][j];
		}
		printf("%d\n",check(hb[A][B]));
	}
	return  0;
} 
上一篇:利用 Arthas 解决启动 StandbyNameNode 加载 EditLog 慢的问题


下一篇:浅谈数据库高可用性(HA)技术