String HDU

String

 HDU - 4821 

题意:求长串中存在多少个长度为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 }
View Code
原文地址:https://www.cnblogs.com/yijiull/p/7388212.html