题目: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3441
题意:
给定一个长串;
给定n个询问,每个询问给定询问类型和一个段串;
有两种询问类型:
0类型要求输出短串在长串中出现的次数(允许重叠);
1类型要求输出短串在长串中出现的次数(不允许重叠)。
分析:
允许重叠的容易,裸的AC自动机;
不允许重叠的只需这样处理:
记录trie树上每个结尾节点一次匹配是在长串的哪个位置,若这次与上次不重叠则记录。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long llong;
const int tmax=1e5+5;
struct question{
int kind,index;
char s[10];
};
question data[tmax];
struct AC{
int num,ch[6*tmax][30],f[6*tmax],last[6*tmax],val[6*tmax];
int times[6*tmax][2],dep[7*tmax],pos[6*tmax];
void init()
{
num=0;
memset(ch,0,sizeof(ch));
memset(f,0,sizeof(f));
memset(last,0,sizeof(last));
memset(val,0,sizeof(val));
memset(times,0,sizeof(times));
memset(dep,0,sizeof(dep));
memset(pos,-1,sizeof(pos));
return;
}
void insert(char *s,int qN)
{
int u=0,len=strlen(s),id;
for(int i=0;i<len;i++)
{
id=s[i]-'a';
if(!ch[u][id]) ch[u][id]=++num;
u=ch[u][id];
}
val[u]=1;
dep[u]=len;
data[qN].index=u;
return;
}
void getfail()
{
queue<int> Q;
Q.push(0);
int x,u,v;
while(!Q.empty())
{
x=Q.front();Q.pop();
for(int i=0;i<26;i++)
{
u=ch[x][i];
if(!u)
{
ch[x][i]=ch[f[x]][i];
continue;
}
Q.push(u);
if(x==0) continue;
v=f[x];
while(v&&!ch[v][i]) v=f[v];
f[u]=ch[v][i];
last[u]=val[f[u]]?f[u]:last[f[u]];
}
}
return;
}
void find(char *s)
{
memset(times,0,sizeof(times));
int len=strlen(s),u=0,id,j;
for(int i=0;i<len;i++)
{
id=s[i]-'a';
u=ch[u][id];
j=u;
do{
times[j][0]++;
if(i-pos[j]>=dep[j])
{
times[j][1]++;
pos[j]=i;
}
j=last[j];
}while(j);
}
return;
}
}ac;
int main()
{
char s[tmax];
int q,kase=0;
while(scanf("%s",s)==1)
{
ac.init();
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d %s",&data[i].kind,data[i].s);
ac.insert(data[i].s,i);
}
ac.getfail();
ac.find(s);
printf("Case %d\n",++kase);
for(int i=1;i<=q;i++)
if(data[i].kind==0)
printf("%d\n",ac.times[data[i].index][0]);
else
printf("%d\n",ac.times[data[i].index][1]);
printf("\n");
getchar();
}
return 0;
}