题目描述:
这是一道模板题。
给定一个字符串 A 和一个字符串 B,求 B 在 A 中的出现次数。A 和 B 中的字符均为英语大写字母或小写字母。
A中不同位置出现的 B 可重叠。
输入格式:
输入共两行,分别是字符串 A 和字符串 B。
输出格式:
输出一个整数,表示 B 在 A 中的出现次数。
样例输入:
zyzyzyz
zyz
样例输出:
3
数据范围与提示:
1<=A,B的长度<=10^6,A,B仅包含大小写字母
模板题,hash函数思路:
我们选取两个合适的互质常数b,h(b小于h),假设字符串
C
=
c
1
c
2
.
.
.
c
m
C=c_1c_2...c_m
C=c1c2...cm,那么
H
(
C
)
=
(
c
1
b
m
−
1
+
c
2
b
m
−
2
+
.
.
.
+
c
m
b
0
)
m
o
d
h
H(C)=(c_1b^{m-1}+c_2b^{m-2}+...+c_mb^0)modh
H(C)=(c1bm−1+c2bm−2+...+cmb0)modh这里把b看作基数,相当于看作是b进制数,b取值应适宜.
而我们经过预处理
b
1
.
.
.
b
n
b_1...b_n
b1...bn和哈希值后,判断子串就为主串一段字符与匹配字符的哈希值是否相等,即
H
(
C
′
)
=
H
(
C
,
k
+
n
)
−
H
(
C
,
k
)
∗
b
n
H(C')=H(C,k+n)-H(C,k)*b^n
H(C′)=H(C,k+n)−H(C,k)∗bn
预处理 b n b^n bn(注意开unsigned long long)
for(int i=1;i<=1000000;i++){
bb[i]=bb[i-1]*b;
}
主串哈希值
for(int i=1;i<=len1;i++){
ahash[i]=ahash[i-1]*b+(unsigned long long)(s1[i]-'A'+1);
}
模板代码
#include<bits/stdc++.h>
using namespace std;
unsigned long long bb[1000099],ahash[1119999],ss;
int n,b=11,ans=0;
char a;
char s1[1099999],ansa[1000999];
int main(){
scanf("%s%s",s1+1,ansa+1);
bb[0]=1;
for(int i=1;i<=1000000;i++){
bb[i]=bb[i-1]*b;
}
int len1=strlen(s1+1),len2=strlen(ansa+1);
ahash[0]=0;
for(int i=1;i<=len1;i++){
ahash[i]=ahash[i-1]*b+(unsigned long long)(s1[i]-'A'+1);
}
for(int i=1;i<=len2;i++){
ss=ss*b+(unsigned long long)(ansa[i]-'A'+1);
}
for(int i=0;i<=len1-len2;i++){
if(ss==ahash[i+len2]-ahash[i]*bb[len2])ans++;
}
cout<<ans;
return 0;
}