哈希用于字符串处理(快速判断两个字符串是否相同)。先介绍一下哈希的思想:
abc=97∗p2+98∗p1+99∗p0 a b c = 97 ∗ p 2 + 98 ∗ p 1 + 99 ∗ p 0
abd=97∗p2+98∗p1+100∗p0 a b d = 97 ∗ p 2 + 98 ∗ p 1 + 100 ∗ p 0
abcd=97∗p3+98∗p2+99∗p1+100∗p0 a b c d = 97 ∗ p 3 + 98 ∗ p 2 + 99 ∗ p 1 + 100 ∗ p 0
显然我们相当于把字符串变成一个p进制的数(称作这个字符串的哈希值),然后如果这个p进制的数相同就可以确定这两个字符串是相同的。但是我们发现:这个数可能会很大,所以我们只能把这两个数进行取模,限制在int范围内。但是由于取模,哈希值相同的字符串不一定相同。不过在模很大的情况下,哈希值相同,两个字符串是大概率相同的。也就是说,如果只判断两个字符串,我们只用计算两个串的哈希值然后比较是否相同,wa的几率是 1100000000 1 100000000 。
但是还有一类问题,我们需要判断某一个串是否出现过。有一个很直接的想法就是把所有哈希值放到bool数组中,计算一个,判断这个哈希值是否出现过。但是这个时候精度问题就十分感人。这个时候我们就需要双哈希,我们取不同的p和不同的模数,对于一个串计算两个哈希值,如果这两个同时出现过,那么也可以判断这个串出现过了。
哈希的思想是很简单的,但是写法上有技巧(令人窒息,第一次考试写wa了)。
for(int j=0;jj++)
for(int j=0;jj++)
hash=(hash*p+a[j])%mod;
再看一看二维哈希。
然后每个格子乘上该格子的数,然后求矩阵前缀和。之后我们就可以O1查询每个矩阵的哈希值(支持加减)。虽然左上角次数不同,我们把所有次数乘成相同的就行。
有双哈希判断是否出现。
时间限制: 1000 ms 内存限制: 131072 KB
提交数: 33 通过数: 10
给出一个 n×m n × m 的矩阵。让你从中发现一个最大的正方形。使得这样子的正方形在矩阵 中出现了至少两次。输出最大正方形的边长。
第一行两个整数 n n , m m 代表矩阵的长和宽;
接下来 n n 行,每行 m m 个字符(小写字母) ,表示矩阵。
输出一个整数表示满足条件的最大正方形的边长。
5 10
ljkfghdfas
isdfjksiye
pgljkijlgp
eyisdafdsi
lnpglkfkjl
3
对于 30%的数据, n,m≤100 n , m ≤ 100 ;
对于 100%的数据, n,m≤500 n , m ≤ 500 。
正如上面的方法,附上代码:
#include
#include
#include
using namespace std;
struct lxy{
int next;
long long x;
}b[250005];
int head[100005];
long long pr1=97,pr2=233,mod1=94271,mod2=19260819;
int n,m,ans,cnt;
long long p1[250005],p2[250005];
long long hash1[505][505],hash2[505][505];
char s[505][505];
void add(int op,int ed)
{
cnt++;
b[cnt].next=head[op];
b[cnt].x=ed;
head[op]=cnt;
}
bool check(int k)
{
cnt=0;
memset(head,-1,sizeof(head));
memset(b,0,sizeof(b));
long long has1,has2;
for(int i=1;i<=n-k+1;i++)
for(int j=1;j<=m-k+1;j++)
{
has1=hash1[i+k-1][j+k-1]+hash1[i-1][j-1]-hash1[i-1][j+k-1]-hash1[i+k-1][j-1];
has2=hash2[i+k-1][j+k-1]+hash2[i-1][j-1]-hash2[i-1][j+k-1]-hash2[i+k-1][j-1];
has1=has1*p1[(n-i+1)*m-j]%mod1;
has2=has2*p2[(n-i+1)*m-j]%mod2;
has1%=mod1;has2%=mod2;
if(has1<0) has1+=mod1;
if(has2<0) has2+=mod2;
for(int p=head[has1];p!=-1;p=b[p].next)
if(b[p].x==has2)
{
return true;
}
add(has1,has2);
}
return false;
}
void er(int l,int r)
{
int mid=(l+r+1)/2;
if(check(mid)) ans=mid;
if(l==r) return;
if(ans==mid) er(mid,r);
else er(l,mid-1);
}
int main()
{
scanf("%d%d",&n,&m);
long long t1=1,t2=1,ci=0;
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);
p1[0]=1;p2[0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
t1=t1*pr1%mod1;t2=t2*pr2%mod2;
hash1[i][j]=t1;hash2[i][j]=t2;
p1[(i-1)*m+j]=t1;p2[(i-1)*m+j]=t2;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
hash1[i][j]=hash1[i][j]*s[i][j]%mod1;
hash2[i][j]=hash2[i][j]*s[i][j]%mod2;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
hash1[i][j]=(hash1[i][j-1]+hash1[i][j])%mod1;
hash2[i][j]=(hash2[i][j-1]+hash2[i][j])%mod2;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
hash1[i][j]=(hash1[i-1][j]+hash1[i][j])%mod1;
hash2[i][j]=(hash2[i-1][j]+hash2[i][j])%mod2;
}
er(1,min(n,m));
cout<