字符串哈希(二维)-Constellations POJ - 3690

字符串哈希(二维)-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×m0M0qa×b(a<=n,b<=m)qM0

样例及数据范围:
在这里插入图片描述
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<=10001<=q<=1001<=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×mqmultisetn×ma×bmultisetmultisetq

因 为 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要快一些,但冲突概率会大一些。 POJunordered_setmultisetunsigned intunsigned 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值