String
题意:求长串中存在多少个长度为M*L的子串(是由M个长度为L的子串构成的)
算是第一道哈希题了,看的别人的代码
先求出原串左边起到第i位的哈希值h[i],然后枚举起点,计算出前M段,然后利用滑动窗口右移,因此起点只需从1枚举到L即可
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ull unsigned long long 4 const int maxn=100010; 5 const int seed=31; 6 7 char s[maxn]; 8 int M,L; 9 ull h[maxn],base[maxn]; 10 map<ull,int> mp; 11 ull _hash(int l,int r) //求区间l到r的哈希值 12 { 13 return h[r]-h[l-1]*base[r-l+1]; 14 } 15 16 int main() 17 { 18 base[0]=1; 19 for(int i=1;i<maxn;i++) 20 base[i]=base[i-1]*seed; 21 while(scanf("%d%d",&M,&L)!=EOF){ 22 scanf("%s",s+1); 23 int len=strlen(s+1); 24 for(int i=1;i<=len;i++) 25 h[i]=h[i-1]*seed+s[i]-'a'; 26 int ans=0; 27 for(int i=1;i<=L&&i+M*L<=len;i++){ 28 mp.clear(); 29 for(int j=i;j<i+M*L;j+=L){ 30 ull x=_hash(j,j+L-1); 31 mp[x]++; 32 } 33 if(mp.size()==M)ans++; 34 //下面相当于为M段的滑动窗口,每次右移判断是否满足 35 for(int j=i+M*L;j+L-1<=len;j+=L){ 36 ull x=_hash(j,j+L-1); 37 mp[x]++; //右边进来 38 ull y=_hash(j-M*L,j-M*L+L-1); 39 mp[y]--; //左边出去 40 if(mp[y]==0) mp.erase(y); 41 if(mp.size()==M) ans++; 42 } 43 } 44 printf("%d ",ans); 45 } 46 47 }