题意:
给你一个母串,q个询问,每次给你一个子串,设定两个串S,T相等当且仅当
1.|S|=|T|
2.S[0]=T[0]&&S[len-1]=T[len-1]
3.S与T的组成集合相同。
问你母串中有多少个子串
题解:
其它都想到了啊,但是怎么哈希没有想到,一般的哈希是
h
=
h
∗
p
+
s
[
i
]
h=h*p+s[i]
h=h∗p+s[i]
这种形式,它可以判断先后,但是这道题它不要求先后,然后我就查到了一个很神奇的做法:
h
=
h
+
p
[
s
[
i
]
]
h=h+p[s[i]]
h=h+p[s[i]]
由多个质数的幂次相加,其实哈希好像就是乱搞,让它能离散分布即可。。
那么这道题就变得非常简单了,对于长度相同的字符串,我们可以把它放在一堆,直接查一次这个长度,那么哈希的次数也就是
n
\sqrt{n}
n级别。然后注意map不能一次次清空,这样会T,我们只记录在查询中有的值。
#include<bits/stdc++.h>
using namespace std;
#define ll unsigned long long
const int N=1e5+5;
ll p[35];
struct node
{
int id,len,sta,en;
ll h;
bool operator< (const node& a)const
{
return len<a.len;
}
}q[N];
char s[N],ss[N];
unordered_map<ll,int>num[26][26];
int ans[N];
void init(int n,int l)
{
ll h=0;
for(int i=0;i<l;i++)
h=h+p[s[i]-'a'+1];
if(num[s[0]-'a'][s[l-1]-'a'].count(h))
num[s[0]-'a'][s[l-1]-'a'][h]++;
for(int i=l;i<n;i++)
{
h+=p[s[i]-'a'+1]-p[s[i-l]-'a'+1];
if(num[s[i-l+1]-'a'][s[i]-'a'].count(h))
num[s[i-l+1]-'a'][s[i]-'a'][h]++;
}
}
int main()
{
p[0]=1;
for(int i=1;i<=26;i++)
p[i]=p[i-1]*101ll;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",s);
int n,lens=strlen(s);
for(int i=0;i<26;i++)
for(int j=0;j<26;j++)
num[i][j].clear();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",ss);
int len=strlen(ss);
q[i].sta=ss[0]-'a',q[i].en=ss[len-1]-'a',q[i].id=i;
ll h=0;
for(int i=0;i<len;i++)
h=h+p[ss[i]-'a'+1];
q[i].len=len,q[i].h=h;
num[q[i].sta][q[i].en][h]=1;
}
sort(q+1,q+1+n);
for(int i=1;i<=n;i++)
{
if(q[i].len!=q[i-1].len)
init(lens,q[i].len);
ans[q[i].id]=num[q[i].sta][q[i].en][q[i].h];
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]-1);
}
return 0;
}