这题考察对ac自动机深一步的使用。我们知道在利用ac自动机进行模式匹配时,是依据是否到达模式串最后一个字符对应的节点来判断是否出现的,因此是允许模式串相互重叠的。然而这一题出现了新的要求,输入数据会指定串能不能重叠,因此我们还需要保存一下每个串上次出现的位置,来判定是否存在重叠。
这里需要额外注意一个事情,就是说可能会出现两个相同串的不同询问,一次询问重叠,一次不重叠,因此insert时还需要处理一下这个情况,将第二次出现的串标记一下,并将它的id赋值为它第一次出现时给的id。
#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <cstring>
#define fi first
#define se second
#define FIN freopen("in.txt","r",stdin)
#define FIO freopen("out.txt","w",stdout)
#define INF 0x3f3f3f3f
#define per(i,a,n) for(int i = a;i < n;i++)
#define rep(i,a,n) for(int i = n;i > a;i--)
#define pern(i,a,n) for(int i = a;i <= n;i++)
#define repn(i,a,n) for(int i = n;i >= a;i--)
#define fastio std::ios::sync_with_stdio(false)
#define all(a) a.begin(), a.end()
#define ll long long
#define pb push_back
#define endl "\n"
#define pii pair<int,int>
#define sc(n) scanf("%d", &n)
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
template<typename T> inline void _max(T &a,const T b){
if(a<b) a = b;}
template<typename T> inline void _min(T &a,const T b){
if(a>b) a = b;}
using namespace std;
//inline ll read(){
// ll a=0;int f=0;char p=getchar();
// while(!isdigit(p)){f|=p=='-';p=getchar();}
// while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();}
// return f?-a:a;
//}
const int maxn = 100000*6+100;
const int maxnode = 26;
int ch[maxn][maxnode]; //字典树
int cnt[maxn]; //单词出现次数
int sz;
int fail[maxn];
int last[100000+100];
char s[100000+100];
int ty[100000+100];
char ss[100000+100][10];
int vis[100000+100];
int ans[100000+100][2];
void init()
{
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
memset(cnt,0,sizeof(cnt));
//memset(ty,0,sizeof(ty));
memset(last,-1,sizeof(last));
memset(vis,0,sizeof(vis));
memset(ans,0,sizeof(ans));
cnt[0] = 0;
}
void insert(char str[], int len,int id) //插入字符串
{
int u = 0;
per(i, 0, len)
{
int v = str[i]-'a';
if (!ch[u][v])
{
memset(ch[sz], 0, sizeof(ch[sz]));
cnt[sz] = 0;
ch[u][v] = sz++;
}
u = ch[u][v];
}
if(cnt[u] == 0)cnt[u] = id;
else vis[id] = cnt[u];
//在这里我们可以建立一个int-string的映射,以通过节点序号得知这个点是哪个单词的结尾
}
void getfail()
{
//所有模式串已插入完成
queue<int> q;
per(i, 0,maxnode)
{
if (ch[0][i])
{
fail[ch[0][i]] = 0;
q.push(ch[0][i]);
}
}
while (!q.empty())
{
int now = q.front();
q.pop();
per(i, 0, maxnode)
{
if (ch[now][i])
{
fail[ch[now][i]] = ch[fail[now]][i];
q.push(ch[now][i]);
}
else
ch[now][i] = ch[fail[now]][i];
}
//cnt[now] |= cnt[fail[now]];
}
}
int n;
void query()
{
int now = 0;
int len = strlen(s);
per(i,0,len)
{
now = ch[now][s[i]-'a'];
int j = now;
while(j)
{
if(cnt[j]){
ans[cnt[j]][0]++;
int dis = i-last[cnt[j]];
if(dis>=strlen(ss[cnt[j]])){
ans[cnt[j]][1]++;
last[cnt[j]] = i;
}
}
j = fail[j];
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
int startTime = clock();
FIN;
#endif
//fastio;
//忘记初始化是小狗
//freopen("out.txt","w",stdout);
//ios::sync_with_stdio(false);
int T = 0;
while(~scanf("%s",s))
{
init();
sc(n);
pern(i,1,n)
{
scanf("%d%s",&ty[i],&ss[i]);
insert(ss[i],strlen(ss[i]),i);
}
getfail();
query();
printf("Case %d\n", ++T);
pern(i,1,n)
{
if(!vis[i]) printf("%d\n",ans[i][ty[i]]);
else printf("%d\n",ans[vis[i]][ty[i]]);
}
printf("\n");
}
#ifndef ONLINE_JUDGE
printf("\nTime = %dms\n", clock() - startTime);
#endif
return 0;
}