目录
Singing Superstar(字符串hash/AC自动机)
Singing Superstar(字符串hash/AC自动机)
题意:
给一长度 < 1e5 的字符串s,q < 1e5次询问,每次问一个长 < 30 的串 t 在s中出现的次数,
且t不可重叠。
例 : “abababa“中“aba“不相交的出现的次数为2。
思路:
一道简单的字符串题,对母串中所有长度小于等于30的串做字符串哈希,对相同哈希值的串暴力统计答
案,每个询问直接查询对应哈希值的答案。
也可以使用Trie/AC自动机来通过本题,数据范围放的很松,理论复杂度稍劣也能通过。
代码:
字符串hash
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
typedef pair<int,int> PII;
#define re register
inline int read()
{
int ans=0;
char last=' ',ch=getchar();
while(ch<'0'|ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans;
return ans;
}
int buf[105];
inline void write(int i)
{
int p = 0;
if(i == 0) p++;
else while(i)
{
buf[p++] = i % 10;
i /= 10;
}
for(int j = p-1; j >= 0; j--) putchar('0' + buf[j]);
}
const int inf=0x3f3f3f3f;
const double PI = acos(-1);
const int mod=998244353;
int qmi(int m, int k, int p)
{
int res = 1 % p, t = m;
while (k)
{
if (k&1) res = (LL)res * t % p;
t = (LL)t * t % p;
k >>= 1;
}
return res;
}
int gcd(int a,int b)
{
return b ? gcd(b,a%b) : a;
}
const int N=100010;
const int M=N*N;
const ull B=131;
ull h[N],a[N];
ull p[N];
char str[N];
ull get(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",str+1);
int len=strlen(str+1);
p[0]=1;
for(int i=1;i<=len;i++)
{
p[i]=p[i-1]*B;
h[i]=h[i-1]*B+str[i];
}
int n;
scanf("%d",&n);
map<ull,int>ma;//记录不相交出现了几次
map<ull,int>last;//记录上一次出现的末尾位置
for(int i=1;i<=n;i++)
{
char s[35];
scanf("%s",s+1);
//cout<<s+1<<endl;
int siz=strlen(s+1);
ull x=0;
for(int j=1;j<=siz;j++)
{
x=x*B+s[j];
}
a[i]=x;
ma[a[i]]=0;
last[a[i]]=0;
}
for(int i=1;i<=len;i++)
{
for(int j=0;j<30&&i+j<=len;j++)
{
ull x=get(i,i+j);
if(ma.count(x)&&last[x]<i)
{
ma[x]++;
last[x]=i+j;
}
}
}
for(int i=1;i<=n;i++)
{
printf("%d\n",ma[a[i]]);
}
}
return 0;
}
AC自动机不重叠:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>
#define myself i,l,r
#define lson i<<1
#define rson i<<1|1
#define Lson i<<1,l,mid
#define Rson i<<1|1,mid+1,r
#define half (l+r)/2
#define inff 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define me(a,b) memset(a,b,sizeof(a))
#define min4(a,b,c,d) min(min(a,b),min(c,d))
#define min3(x,y,z) min(min(x,y),min(y,z))
#define max4(a,b,c,d) max(max(a,b),max(c,d))
#define max3(x,y,z) max(max(x,y),max(y,z))
typedef long long ll;
using namespace std;
const int maxn=6e5+5;
const int maxm=1e5+10;
const int N=26;
int ans[maxn];//记录答案
int op[maxn];
int val[maxn];//记录节点末尾位置
struct AC
{
int fail[maxn];
int last[maxn];
int pos[maxn];//记录单词对应的长度
int ch[maxn][30];
int cnt,root;
int newnode()
{
for(int i=0;i<N;i++)
ch[cnt][i]=0;
pos[cnt]=fail[cnt++]=0;
return cnt-1;
}
void init()
{
cnt=0;
root=newnode();
}
void insert(char *s,int x)
{
int len=strlen(s);
int u=0;
for(int i=0;i<len;i++)
{
int v=s[i]-'a';
if(!ch[u][v])
ch[u][v]=newnode();
u=ch[u][v];
pos[u]=i+1;
}
val[x]=u;
}
void getfail()
{
queue<int >q;
int u=0;
for(int i=0;i<N;i++)
if(ch[u][i])
q.push(ch[u][i]);
while(!q.empty())
{
u=q.front();
q.pop();
for(int i=0;i<N;i++)
{
if(ch[u][i])
{
fail[ch[u][i]]=ch[fail[u]][i];
q.push(ch[u][i]);
}
else
ch[u][i]=ch[fail[u]][i];
}
}
}
void getans(char *s)
{
memset(last,-1,sizeof(last));
memset(ans,0,sizeof(ans));
int len=strlen(s);
int u=0;
for(int i=0;i<len;i++)
{
u=ch[u][s[i]-'a'];
for(int j=u;j;j=fail[j])
{
if(i-last[j]>=pos[j])//看看当前位置与之前到达该点的位置差是否大于单词长度
{
ans[j]++;
last[j]=i;
}
}
}
}
}AC;
char str[maxm];
char ss[40];
int main()
{
int n,cas=0;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",str);
AC.init();
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%s",ss);
AC.insert(ss,i);
}
AC.getfail();
AC.getans(str);
for(int i=0;i<n;i++)
printf("%d\n",ans[val[i]]);
}
}