给一个大串和若干个小串,问大串有多少个子串不包含任何小串。只要两个子串是不同位置的就认为是不同的子串。
AC自动机。用所有的子串减去不符合要求的子串。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int K=26;
const int N=100010;
struct Node {
Node *ch[K],*fail;
int match,len,h;
Node () {
memset(this,0,sizeof(Node));
}
void *operator new (size_t,void *p) {
return p;
}
};
Node *que[N];
Node nodes[N],*root,*superRoot,*cur;
void clear() {
cur=nodes;
superRoot=new(cur++)Node();
root=new(cur++)Node();
root->h=0;
root->fail=superRoot;
for (int i=0;i<K;i++) superRoot->ch[i]=root;
superRoot->match=-1;
}
void insert(char *s) {
Node *t=root;
for (;*s;s++) {
int x=*s-'a';
if (t->ch[x]==NULL) {
t->ch[x]=new(cur++)Node();
t->ch[x]->h=t->h+1;
}
t=t->ch[x];
}
t->match++;
}
void build() {
int p=0,q=0;
que[q++]=root;
superRoot->len=-1;
while (p!=q) {
Node *t=que[p++];
if (t->fail->len==-1&&t->match!=0) t->len=t->h;
else t->len=t->fail->len;
for (int i=0;i<K;i++) {
if (t->ch[i]) {
t->ch[i]->fail=t->fail->ch[i];
que[q++]=t->ch[i];
} else t->ch[i]=t->fail->ch[i];
}
}
}
char s[1000001];
char s2[100001];
int ls,n,last;
long long ans;
int main() {
int t,tt,i;
scanf("%d",&t);
for (tt=1;tt<=t;tt++) {
clear();
scanf("%s",s);
ls=strlen(s);
scanf("%d",&n);
for (i=0;i<n;i++) {
scanf("%s",s2);
insert(s2);
}
ans=(long long)ls*(ls+1)/2;
build();
Node *t=root;
last=0;
for (i=0;i<ls;i++) {
t=t->ch[s[i]-'a'];
if (t->len!=-1) {
last=max(last,i-t->len+2);
}
ans-=last;
}
printf("Case #%d: %lld\n",tt,ans);
}
return 0;
}