给一个串S和一些串s1,s2,...,sn,问是S的子串且不是s1,s2,...,sn中任何一个的子串的字符串有多少个?出现在S的不同位置的相同子串算一个。
后缀自动机,先用S跑一个后缀自动机,然后在这个自动机上跑s1,s2,...,sn,记录每个节点被s1,s2,...,sn访问到的最大长度。最后用原来的最大长度减去后来被访问到的最大长度,得到的就是不重复的子串个数。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int K=26;
const int N=100000;
inline int toint(char c) {
return c-'a';
}
struct SANode {
SANode *f;
SANode *son[K];
int maxl,l;
SANode *clear(int ll=0) {
f=NULL;
for (int i=0;i<K;i++) son[i]=NULL;
maxl=ll;
return this;
}
};
SANode b[2*N+2];
SANode *bp,*tail,*init;
void clear() {
bp=b;
init=tail=(bp++)->clear();
}
void push_back(char c) {
int x=toint(c);
SANode *i=tail;
tail=(bp++)->clear(i->maxl+1);
for (;i&&!i->son[x];i=i->f) i->son[x]=tail;
if (!i) tail->f=init;
else if (i->maxl+1==i->son[x]->maxl) tail->f=i->son[x];
else {
SANode *p=(bp++)->clear(),*q=i->son[x];
*p=*q;
q->f=tail->f=p;
p->maxl=i->maxl+1;
for (;i&&i->son[x]==q;i=i->f) i->son[x]=p;
}
}
void repair() {
for (SANode *it=b+1;it!=bp;it++) it->l=it->f->maxl;
}
void add(char *s) {
int x,l=0;
SANode *i=init;
while (*s!='\0') {
x=toint(*s);
if (i->son[x]) {
i=i->son[x];
l++;
i->l=max(i->l,l);
} else {
while (i&&!i->son[x]) i=i->f;
if (!i) {
i=init;
l=0;
} else {
l=i->maxl+1;
i=i->son[x];
i->l=max(i->l,l);
}
}
for (SANode *j=i->f;j&&j->l!=j->maxl;j=j->f) j->l=j->maxl;
s++;
}
}
long long getans() {
long long ans=0;
for (SANode *it=b+1;it!=bp;it++) ans+=it->maxl-it->l;
return ans;
}
char s[100001];
int main() {
int t,tt,i,n;
scanf("%d",&t);
for (tt=1;tt<=t;tt++) {
scanf("%d",&n);
scanf("%s",s);
clear();
for (i=0;s[i]!='\0';i++) push_back(s[i]);
repair();
while (n--) {
scanf("%s",s);
add(s);
}
printf("Case %d: %lld\n",tt,getans());
}
return 0;
}