​传送门​

题意:

给出一个长度为2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++的字符串和2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_子串_02个长度2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_字符串_03的子串,求每个子串在模式串中的最大不相交出现次数;

思路:

  • 大概是2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_字符串_04自动机模板题?
  • 下面说一下哈希的做法:
  • 有一个很重要的地方就是子串的长度是2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_05的,也就是说我们完全可以枚举模式串中长度为2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_06的字符串,通过比较哈希值来看这段字符串是不是子串,时间复杂度大概2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_07
  • 这样没有办法处理的问题就是如何保证不相交了。
  • 2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_08表示哈希值为2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_09的字符串在模式串中的上一个出现位置(记录的是尾端字符所在的位置)。比如2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_子串_10,当枚举到2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_11的时候,子串为2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_子串_12
  • 这样每次遍历的时候,只需要判断2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_字符串_13是否成立就好了;
  • 简单说一下正确性,这样处理的目的是避免相交的子串,但是怎么能够保证这样是最优的呢?
  • 如果有某个子串出现了奇数次,比如2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_字符串_14,其中2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_15出现了2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_子串_16次,按照上述算法,中间的2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_15会被忽略掉,最后答案为2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_子串_18次;
  • 如果有某个子串出现了偶数次,比如2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_19,其中2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_15出现了2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_字符串_21次,按照上述算法,第二个和第四个的2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_i++_15会被忽略掉,最后答案为2021杭电多校第八场 HDU7064-Singing Superstar(哈希)_子串_18次;
  • 这两种都是最优的。

代码:

const int N=4e5+7,P=131;

ull h[N], p[N],a[N];
char str[N];
ull th[50],tp[50];
ull get(int l, int r)
{
return h[r]-h[l-1]*p[r-l+1];
}

int main(){
int _=read;
while(_--){
scanf("%s",str+1);
p[0]=1;h[0]=0;
int len=strlen(str+1);
for(int i=1;i<=len;i++){
h[i] = h[i - 1] * P + str[i];
p[i] = p[i - 1] * P;
//cout<<h[i]<<endl;
}
unordered_map<ull,int>mp,las;
int n=read;
rep(i,1,n){
char s[35];cin>>s+1;
tp[0]=1;th[0]=0;
for(int j=1;j<=strlen(s+1);j++){
th[j]=th[j-1]*P+s[j];
tp[j]=tp[j-1]*P;
}
a[i]=th[strlen(s+1)];
mp[a[i]]=0;
las[a[i]]=0;
//cout<<a[i]<<endl;
}
for(int i=1;i<=len;i++){
for(int j=0;j<30&&i+j<=len;j++){
ull now=get(i,i+j);
//if(i==1&&j==2) cout<<now<<endl;
if(mp.count(now)){
if(las[now]<i) mp[now]++,las[now]=i+j;
}
}
}
rep(i,1,n) printf("%d\n",mp[a[i]]);
}
return 0;
}