主要考察的是对AC自动机的理解。
首先不重复直接匹配
否则定义Last表示以此结尾的串上一次所在匹配位置
Pos表示这个字符在当前串位置
若i-Last>Pos 则这是合法解
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=6e5+100;
struct AUTO{
int cnt;
int Stop[N];
int Ans[N][2];
struct Node{
int vis[26];
int fail;
int end;
}AC[N];
int last[N];
int pos[N];
inline void Clear(int Id){
memset(AC[Id].vis,0,sizeof(AC[Id].vis));
AC[Id].fail=AC[Id].end=0;
}
inline void Insert(string S,int Id){
int len=S.length();
int now=0;
for(int i=0;i<len;i++){
if(!AC[now].vis[S[i]-'a']){
cnt++;
Clear(cnt);
AC[now].vis[S[i]-'a']=cnt;
}
now=AC[now].vis[S[i]-'a'];
pos[now]=i+1;
}
Stop[Id]=now;
}
inline void GetFail(){
queue<int> Q;
for(int i=0;i<26;i++){
if(AC[0].vis[i]){
AC[AC[0].vis[i]].fail=0;
Q.push(AC[0].vis[i]);
}
}
while(!Q.empty()){
int u=Q.front();
Q.pop();
for(int i=0;i<26;i++){
if(AC[u].vis[i]){
AC[AC[u].vis[i]].fail=AC[AC[u].fail].vis[i];
Q.push(AC[u].vis[i]);
}
else AC[u].vis[i]=AC[AC[u].fail].vis[i];
}
}
}
inline void Query(string S){
int len=S.length();
int now=0;
for(int i=0;i<len;i++){
now=AC[now].vis[S[i]-'a'];
for(int t=now;t;t=AC[t].fail){
Ans[t][0]++;
if(i-last[t]>=pos[t]){
Ans[t][1]++;
last[t]=i;
}
}
}
}
}AC;
string S;
string ch;
int opt[N];
int n;
int main(){
int Id=0;
while(cin>>S){
AC.Clear(0);
AC.cnt=0;
memset(AC.Ans,0,sizeof(AC.Ans));
memset(AC.Stop,0,sizeof(AC.Stop));
memset(AC.last,-1,sizeof(AC.last));
memset(AC.pos,0,sizeof(AC.pos));
cin>>n;
for(int i=1;i<=n;i++){
cin>>opt[i];
cin>>ch;
AC.Insert(ch,i);
}
AC.GetFail();
AC.Query(S);
cout<<"Case "<<(++Id)<<'\n';
for(int i=1;i<=n;i++){
cout<<AC.Ans[AC.Stop[i]][opt[i]]<<'\n';
}
cout<<'\n';
}
}