字符串哈希(二维)-Constellations POJ - 3690
公 式 推 导 公式推导 公式推导——《二维哈希》
题意:
输 入 一 个 n × m 的 由 ′ ∗ ′ 和 ′ 0 ′ 构 成 的 矩 阵 M 0 , 接 着 输 入 q 个 a × b 的 矩 阵 ( a < = n , b < = m ) , 求 这 q 个 矩 阵 中 , 有 多 少 个 矩 阵 是 M 0 的 子 矩 阵 。 输入一个n×m的由'*'和'0'构成的矩阵M_0,接着输入q个a×b的矩阵(a<=n,b<=m),\\求这q个矩阵中,有多少个矩阵是M_0的子矩阵。 输入一个n×m的由′∗′和′0′构成的矩阵M0,接着输入q个a×b的矩阵(a<=n,b<=m),求这q个矩阵中,有多少个矩阵是M0的子矩阵。
样例及数据范围:
1
<
=
n
,
m
<
=
1000
,
1
<
=
q
<
=
100
,
1
<
=
a
,
b
<
=
50
。
1<=n,m<=1000,1<=q<=100,1<=a,b<=50。
1<=n,m<=1000,1<=q<=100,1<=a,b<=50。
具体落实:
① 、 可 以 在 输 入 n × m 的 矩 阵 的 同 时 , 对 其 每 一 行 单 独 进 行 哈 希 , 为 ③ 预 处 理 准 备 。 ② 、 再 求 q 个 小 矩 阵 的 哈 希 值 , 用 m u l t i s e t 来 保 存 。 ③ 、 然 后 求 整 个 n × m 的 矩 阵 中 所 有 的 a × b 的 子 矩 阵 的 哈 希 值 , 同 时 在 m u l t i s e t 中 删 除 对 应 的 元 素 。 ④ 、 最 后 m u l t i s e t 中 剩 下 没 有 被 删 掉 的 元 素 就 是 未 能 匹 配 成 功 的 子 矩 阵 , 答 案 为 输 入 的 子 矩 阵 的 个 数 q 减 去 容 器 中 剩 余 元 素 的 个 数 。 ①、可以在输入n×m的矩阵的同时,对其每一行单独进行哈希,为③预处理准备。\\②、再求q个小矩阵的哈希值,用multiset来保存。\\③、然后求整个n×m的矩阵中所有的a×b的子矩阵的哈希值,同时在multiset中删除对应的元素。\\④、最后multiset中剩下没有被删掉的元素就是未能匹配成功的子矩阵,\\\qquad答案为输入的子矩阵的个数q减去容器中剩余元素的个数。 ①、可以在输入n×m的矩阵的同时,对其每一行单独进行哈希,为③预处理准备。②、再求q个小矩阵的哈希值,用multiset来保存。③、然后求整个n×m的矩阵中所有的a×b的子矩阵的哈希值,同时在multiset中删除对应的元素。④、最后multiset中剩下没有被删掉的元素就是未能匹配成功的子矩阵,答案为输入的子矩阵的个数q减去容器中剩余元素的个数。
因 为 P O J 不 支 持 u n o r d e r e d _ s e t , 所 以 本 题 采 用 了 m u l t i s e t 。 另 外 , u n s i g n e d i n t 处 理 起 来 要 比 u n s i g n e d l o n g l o n g 要 快 一 些 , 但 冲 突 概 率 会 大 一 些 。 因为POJ不支持unordered\_set,所以本题采用了multiset。\\另外,unsigned\ int处理起来要比unsigned\ long\ long要快一些,但冲突概率会大一些。 因为POJ不支持unordered_set,所以本题采用了multiset。另外,unsigned int处理起来要比unsigned long long要快一些,但冲突概率会大一些。
神 奇 发 现 : 似 乎 对 容 器 只 进 行 删 除 插 入 操 作 要 比 询 问 要 快 . . . 神奇发现:似乎对容器只进行删除插入操作要比询问要快... 神奇发现:似乎对容器只进行删除插入操作要比询问要快...
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<set>
#define ull unsigned int
using namespace std;
const int N=1010;
const int base=131;
int n,m,q,a,b;
ull h[N][N],p[2510];
char str[N];
ull get(ull h[],int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
int T=1;
while(~scanf("%d%d%d%d%d",&n,&m,&q,&a,&b),n||m||q||a||b)
{
multiset<ull> S;
for(int i=1;i<=n;i++)
{
scanf("%s",str+1);
for(int j=1;j<=m;j++)
h[i][j]=h[i][j-1]*base+str[j]-'0';
}
p[0]=1;
for(int i=1;i<=a*b;i++) p[i]=p[i-1]*base;
for(int k=1;k<=q;k++)
{
///计算输入的子矩阵的值
ull s=0;
for(int i=1;i<=a;i++)
{
scanf("%s",str+1);
for(int j=1;j<=b;j++)
s=s*base+str[j]-'0';
}
S.insert(s);
}
///j枚举右端点,求所有a×b的子矩阵哈希值
for(int j=b;j<=m;j++)
{
ull s=0;
int l=j-b+1,r=j;
for(int i=1;i<=n;i++) ///按列求哈希
{
s=s*p[b]+get(h[i],l,r);
if(i-a>0) s-=get(h[i-a],l,r)*p[a*b];
if(i-a>=0) S.erase(s);
}
}
printf("Case %d: %d\n",T++,q-S.size());
}
return 0;
}