字符串哈希(BKDR)——例题

BKDR_Hash

字符串的哈希值采取前缀和方式计算

选择数字P = 31作为优质乘子

str:NULLabcdef
hash0
下标0123456
hash[0] = 0;
hash[1] = hash[0] * P + str[1];
hash[2] = hash[1] * P + str[2];
hash[3] = hash[2] * P + str[3];
…………………………
hash[6] = hash[5] * P + str[6];

最终hash[6]存放的就是整个字符串的哈希值。

在计算哈希值的过程中可能会爆数据,这时就要采取措施保证数据正确性!选择unsigned long long类型可以自动对 2 64 2^{64} 264取模。(最大存储数值为 2 64 − 1 2^{64}-1 2641,也就是全1状态,加1之后全清0)

无符号整数较小值减较大值问题?

在这里插入图片描述

那么无符号整型 2 − 4294967295 2-4294967295 24294967295是否等于3呢?

− 4294967295 -4294967295 4294967295等于 − 1111...1111 -1111...1111 1111...1111从最后一个1的前一位开始取反得到 0000...0001 0000...0001 0000...0001也就是等于1

最后2+1确实等于3!!!

再测几组数:

无符号整型 1 − 2 1-2 12 2 : 0000...0010     − 2 : 1111...1110   +   1   =   1111...1111 ( 4294967295 ) 2:0000...0010\ \ \ -2:1111...1110\ +\ 1 \ =\ 1111...1111(4294967295) 2:0000...0010   2:1111...1110 + 1 = 1111...1111(4294967295)

无符号整型 1 − 3 1-3 13 3 : 0000...0011     − 3 : 1111...1101   +   1   =   1111...1110 ( 4294967294 ) 3:0000...0011\ \ \ -3:1111...1101\ +\ 1 \ =\ 1111...1110(4294967294) 3:0000...0011   3:1111...1101 + 1 = 1111...1110(4294967294)

无符号整型小数减大数根据Mod P的值可逆

  • 辅助理解哈希

将字符串“654321”===>十进制

str:NULL654321
hash0
下标0123456
hash[0] = 0;
hash[1] = hash[0] * 10 + str[1] = 6
hash[2] = hash[1] * 10 + str[2] = 65
hash[3] = hash[2] * 10 + str[3] = 654
…………………………
hash[6] = hash[5] * 10 + str[6] = 654321

最终hash[6]存放的就是整个字符串的哈希值(前缀和方式计算)。

如何取子串的hash值?

子串区间 [ l , r ] 子串区间[l, r] 子串区间[l,r]
h a s h [ r ] − h a s h [ l − 1 ] ∗ p ( r − l + 1 ) hash[r] - hash[l - 1] * p ^{(r - l + 1)} hash[r]hash[l1]p(rl+1)

海贼oj 275 兔子和兔子

aabbaabb
3
1 3 5 7
1 3 6 8
1 2 1 2
    
Yes
No
Yes
   
输入l1 r1 l2 r2,判断[l1, r1]区间的字符串是否等于[l2, r2]
/*************************************************************************
        > File Name: h275.cpp
        > Author: luzelin
        > Mail: luzelin1024@163.com
        > Created Time: Sun 30 Oct 2022 01:18:11 PM CST
 ************************************************************************/

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int N = 1e6;

#define int unsigned long long

int BKDR[N + 5], PPow[N + 5], P = 31;
char str[N + 5];

void Init_BKDR() {
    PPow[1] = P;
    for (int i = 1; str[i]; ++i) {
        BKDR[i] = BKDR[i - 1] * P + (int)str[i];
        if (i - 1)  PPow[i] = PPow[i - 1] * P;
    }
    return ;
}

#define BKDR(left, right) ({\
    BKDR[right] - BKDR[left - 1] * PPow[right - left + 1];\
})

signed main() {
    scanf("%s", str + 1);
    Init_BKDR();
    int m, ll, lr, rl, rr;
    scanf("%llu", &m);
    while (m--) {
        scanf("%llu%llu%llu%llu", &ll, &lr, &rl, &rr);
        if (BKDR(ll, lr) == BKDR(rl, rr))  puts("Yes");
        else  puts("No");
    }
    return 0;
}

#undef int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值