AcWing:841. 字符串哈希

92 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第33天,点击查看活动详情

AcWing:841. 字符串哈希

841. 字符串哈希

给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l1,r1,l2,r2,请你判断 [l1,r1] 和 [l2,r2] 这两个区间所包含的字符串子串是否完全相同。

字符串中只包含大小写英文字母和数字。

输入格式

第一行包含整数 n 和 m,表示字符串长度和询问次数。

第二行包含一个长度为 n 的字符串,字符串中只包含大小写英文字母和数字。

接下来 m 行,每行包含四个整数 l1,r1,l2,r2,表示一次询问所涉及的两个区间。

注意,字符串的位置从 1 开始编号。

输出格式

对于每个询问输出一个结果,如果两个字符串子串完全相同则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1≤n,m≤10^5

输入样例:

8 3
aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2

输出样例:

Yes
No
Yes

问题解析

首先我们可以想一想,为什么一个十进制数是独一无二的?

比如对于123来说,因为满足百位数是1,十位数是2,个数为是3的三位数就只有123一个了。

对于同一进制来说,只要各个位的数字是固定的,那么最后得到的数就肯定是同一个。

字符串哈希其实就是把字符串转化成一个base进制下的数,我们判断两个数一不一样就是看他们大小是否相等,那么对应的,如果两个字符串转化成的数相等,就能说明这两个字符串是一样的。

AC代码

#include<iostream>
using namespace std;
#include<vector>
​
typedef unsigned long long ull;
int n,m,p=99971,base=13331;
​
ull get_hash(vector<ull>&v,int l,int r,vector<ull>&bpow)
{
    ull t=v[l-1]*bpow[r-l+1];
    return (v[r]-t);
}
​
int main()
{
    cin>>n>>m;
    string str;
    cin>>str;
    vector<ull>v(n+1),bpow(n+1,1);
    ull res=0;
    for(int i=1;i<=n;i++)
    {
        res=(res*base+str[i-1]);
        v[i]=res;
        bpow[i]=bpow[i-1]*base;
    }
    while(m--)
    {
        int l1,l2,r1,r2;
        cin>>l1>>r1>>l2>>r2;
        if(str[l1-1]!=str[l2-1]||str[r1-1]!=str[r2-1])
        {
            cout<<"No"<<endl;
            continue;
        }
        ull x=get_hash(v,l1,r1,bpow);
        ull y=get_hash(v,l2,r2,bpow);
        if(x==y)
        {
            cout<<"Yes"<<'\n';
        }
        else cout<<"No"<<'\n';
    }
    return 0;
}