bzoj2351 [BeiJing2011]Matrix(二维hash)

题意

给定一个M行N列的01矩阵,以及Q个A行B列的01矩阵,你需要求出这Q个矩阵哪些在原矩阵中出现过。

我的想法

hash
在不知道二维hash前,我想把一个二维矩阵转为一维的序列再hash。
实现中却出现了除法,一想发现hash不能除。因为hash值本身就是模数,除法不满足同余定律。所以hash值只能通过加减乘来变化。
代码放着,哪位神犇做出来了也告诉我一声。

WA代码

#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
const int maxl=1010;
const ull P=131;ull power[100*maxl];

int n,m,a,b;
ull hash[maxl][maxl];
map<ull,bool> v;

char s[maxl];
int main()
{
	power[0]=1;for(int i=1,imax=100*maxl;i<imax;i++) power[i]=power[i-1]*P;
	scanf("%d%d%d%d",&n,&m,&a,&b);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for(int j=1;j<=b;j++) hash[i][j]=hash[i][j-1]*P+s[j];
		for(int j=b+1;j<=m;j++) hash[i][j]=hash[i][j-1]*P+s[j] - s[j-b]*power[b];
	}
	
	for(int x=n-a+1,y=b;y<=m;y++)
	{
		for(int i=x+1;i<=n;i++) hash[x][y]=hash[x][y]*power[b]+hash[i][y];
		v[hash[x][y]]=true;
	}
	
	for(int x=n-a;x>=1;x--)
	{
		for(int y=b;y<=m;y++)
		{
			hash[x][y]=hash[x+1][y]/power[b]+hash[x][y]*power[b*(a-1)];
			v[hash[x][y]]=true;
		}
	}
	
	int Q;
	scanf("%d",&Q);
	while(Q--)
	{
		ull h=0;
		for(int i=1;i<=a;i++)
		{
			scanf("%s",s+1);
			for(int j=1;j<=b;j++) h=h*P+s[j];
		}
		if(v[h]==true) puts("1");
		else puts("0");
	}
	return 0;
}

题解

二维hash
膜了其他人的题解后,终于发现hash还有K维。
对于2维hash,我们有两种理解方式。
第一种,整体理解:取两个进制值P1,P2,先对每一行进行hash。以hash值为新的值,对每一列进行hash。这就是二维hash。
第二种,个体理解:直接点,对于二维数据中的一个点s[x][y](0<=x,y),把s[x][y]*P_2^x*P_1^y加入整体的hash值中。

二维hash这样一个好处,它可以用容斥原理O(1)求出其中一个矩阵的hash值。利用这点就可以解决这题了。

代码

#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
const int maxl=1010;
const ull P1=131;ull power1[maxl];//用于列m b 
const ull P2=139;ull power2[maxl];//用于行n a

int n,m,a,b;
int s[maxl][maxl];
ull hash[maxl][maxl];
map<ull,bool> v;

int main()
{
    scanf("%d%d%d%d",&n,&m,&a,&b);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) scanf("%1d",&s[i][j]);
    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) hash[i][j]=hash[i][j-1]*P1+s[i][j];
    for(int j=1;j<=m;j++)
        for(int i=1;i<=n;i++) hash[i][j]=hash[i-1][j]*P2+hash[i][j];
    
    power1[0]=1;for(int i=1;i<=m;i++) power1[i]=power1[i-1]*P1;
    power2[0]=1;for(int i=1;i<=n;i++) power2[i]=power2[i-1]*P2;
    
    for(int i=a;i<=n;i++)
        for(int j=b;j<=m;j++)
        {
            ull tmp;
            tmp=hash[i][j]-hash[i-a][j]*power2[a]-hash[i][j-b]*power1[b]+hash[i-a][j-b]*power2[a]*power1[b];
            v[tmp]=true;
        }
    
    int Q;
    scanf("%d",&Q);
    while(Q--)
    {
        ull h=0;
        for(int i=1;i<=a;i++)
        {
            for(int j=1;j<=b;j++)
            {
                scanf("%1d",&s[i][j]);
                h+=s[i][j]*power2[a-i]*power1[b-j];
            }
        }
        if(v[h]==true) puts("1");
        else puts("0");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/81626115