字符串哈希

1、字符串哈希
其实就是把每个字符转换成ASCLL码,然后就把这个字符串当成一个某(base)进制的数字,再转换成十进制。
每个数字要乘它的权重(第一个的权重是很多次幂,是通过前缀加循环的方式实现的,而不是直接乘一个高次幂)

1、字符串的哈希值核心板子:

typedef unsigned long long ull; //基本都是无符号数
ull base=131;//都喜欢用这个质数。要么131,要么29
ull prime=233317; //单哈希的辅助数(可以不写)
ull M=212370440130137957ll;//最大的用来取模的数(越大越好的,这个就是最大)
ull hashs(string s)
{
    int len=s.size();
    ull ans=0;
    for (int i=0;i<len;i++)
         //自然溢出 ans=ans*base+(ull)s[i];//一般都是用ASCLL码
	//单哈希(最常用)ans=(ans*base+(ull)s[i])%M+prime;  
	//双哈希(正确性最高,感觉出不到这个)就是再弄一个ans,但是换个底数(一般就29和131)
    return ans;//如果你想得到各个子串的哈希值,那就要用前缀数组(存ans就行)还是不需要递推 
}
//ans即为本字符串的哈希值

2、构造前缀哈希值数组和后缀哈希值数组
全局:

const int N=1e6+5,mod=1e9+7,P=131;//P是底,mod也可以是上面那个M(越大越好)
int n;
int h1[N],h2[N],p[N];//P是记录base数组,用于计算区间哈希值
char s[N];

函数:

void make_hash(){
    p[0]=1,h1[0]=0;
    for(int i=1;i<=n;i++){
        h1[i]=(h1[i-1]*P%mod+s[i])%mod;
        p[i]=p[i-1]*P%mod; 
    }
     
    h2[n+1]=0;
    for(int i=n;i>=1;i--){
        h2[i]=(h2[i+1]*P%mod+s[i])%mod;
    }
}

主函数里要这么写

cin>>s+1;//**直接从1开始输入的,所以这个板子里的下标均从1开始**
n=strlen(s+1); 
make_hash();

3、得到一个区间l到r的前缀值

int get1(int l,int r)
{
    return (h1[r]%mod-h1[l-1]%mod*p[r-l+1]%mod+mod)%mod;
}

4、得到一个区间l到r的后缀值

int get2(int l,int r)
{
    return (h2[l]%mod-h2[r+1]%mod*p[r-l+1]%mod+mod)%mod;
}
posted @ 2024-04-15 12:11  涤生yang  阅读(25)  评论(0)    收藏  举报