比赛时居然没拍出来~~
首先,利用主串 构造一个后缀自动机。 然后利用拓扑序 计算出 从s(初态)出发到达每个节点所构成的子串在主串中出现过几次(就是将parent树中的,儿子状态出现次数加给他的parent ,因为parent树中parent的状态是他的儿子节点的状态并集,不懂看clj的ppt~~~)。
构造出来以后,将要匹配的串 例如abc 改成 abcab ,将abcab拿去匹配。 如果匹配的长度为 strlen(abc) 那么答案就加上 当前匹配到的节点状态的出现次数。
#include<stdio.h>
#include<string.h>
#include <cmath>
#include<algorithm>
#define fr(i,s,n) for(int i=s;i<n;i++)
#define fi freopen("in.txt","r",stdin)
#define fo freopen("output.txt","w",stdout)
#define cl(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=2000010;
const int kinds=26;
char ch[maxn];
struct Sam{
Sam *son[kinds],*fa;
int l ,cnt;
bool vst;
}a[maxn],*head,*last;
int top=-1;
void add(int x){
Sam *p=&a[++top],*bj=last;
p->l=last->l+1;last=p;
for(; bj && !bj->son[x] ; bj = bj->fa) bj->son[x] = p;
if (!bj) p->fa = head;
else if (bj->l+1 == bj->son[x]->l) p->fa = bj->son[x];
else{
Sam *r = &a[ ++ top],*q = bj->son[x];
*r = *q ,r->l= bj->l+1, p->fa = q->fa = r;
for( ; bj && bj->son[x] == q; bj = bj->fa) bj->son[x] = r;
}
}
Sam *b[maxn];
int dws[maxn],len;
Sam *sta[maxn];
int main(){
scanf("%s",ch);
head = last = &a[++top];
int n=strlen(ch);
fr(i,0,n) add( ch[i] - 'a');
int i;
for (i = 0; i <= top; ++i) ++dws[a[i].l];
for (i = 1; i <= n; ++i) dws[i] += dws[i - 1];
for (i = 0; i <= top; ++i) b[--dws[a[i].l]] = &a[i];
for (last = head, i = 0; i < n; ++i)
(last = last->son[ch[i] - 'a'])->cnt++;
for (i = top; i > 0; --i){
b[i]->fa->cnt += b[i]->cnt;
}
int q,l;
scanf("%d",&q);
fr(i,0,top+1) a[i].vst = 0;
fr(k,0,q){
int statop = 0;
int ans=0;
scanf("%s",ch);
l = len = strlen(ch);
fr(i , 0 ,len) ch[len + i] = ch[i];
len<<=1;--len;ch[len] = '\0';
int mid = 0, y;
last = head;
fr(i,0,len){
if (last ->son[y = ch[i] - 'a' ]){
++ mid;
last = last->son[y];
while(last->fa->l >= mid )
last = last->fa;
if (mid == l) {
if (!last->vst) last->vst = 1,ans += last->cnt,sta[statop++] = last;
--mid;
}
}
else {
for (; last && !last->son[y]; last = last->fa);
if (!last) mid = 0,last = head;
else{
mid = last->l + 1;
last = last->son[y];
while(last->fa->l >= mid)
last = last->fa;
if (mid == l) {
if (!last->vst ) last->vst = 1,ans += last->cnt,sta[statop++] = last;
--mid;
}
}
}
}
fr(i,0,statop) sta[i]->vst = 0;
printf("%d\n",ans);
}
return 0;
}