题目大意: 给出 N N N 个字符串,求出每个字符串拥有多少个本质不同的且不被其他字符串包含的子串。
题解
广义后缀自动机裸题,造的时候标记一下包含前缀的状态属于哪个字符串,造出来之后把后缀链接树也造出来,假如一个状态的子树内的所有状态都属于同一个字符串,那么这个状态就只属于哪个字符串,加上他的贡献即可,假如子树内不是都属于同一个字符串,说明这个状态包含的子串在不同的字符串中出现过,就不可能提供贡献了。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 200010
#define ll long long
int T,n,ans[maxn];
char s[maxn];
struct state{
int len,link,next[26],belong;
}st[maxn];
int id=0,last,now,p,q;
void extend(int x,int be)
{
now=++id;
st[now].len=st[last].len+1;st[now].belong=be;
for(p=last;p!=-1&&!st[p].next[x];p=st[p].link)st[p].next[x]=now;
if(p!=-1)
{
q=st[p].next[x];
if(st[p].len+1==st[q].len)st[now].link=q;
else
{
int clone=++id;
st[clone]=st[q];st[clone].len=st[p].len+1;
for(;p!=-1&&st[p].next[x]==q;p=st[p].link)st[p].next[x]=clone;
st[q].link=st[now].link=clone;
}
}
last=now;
}
struct edge{int y,next;};
edge e[maxn];
int first[maxn],len=0;
void buildroad(int x,int y){e[++len]=(edge){y,first[x]};first[x]=len;}
void dfs(int x)
{
for(int i=first[x];i;i=e[i].next)
{
dfs(e[i].y);
if(!st[x].belong)st[x].belong=st[e[i].y].belong;
else if(st[x].belong!=st[e[i].y].belong)st[x].belong=-1;
}
if(st[x].belong!=-1)ans[st[x].belong]+=st[x].len-st[st[x].link].len;
}
int main()
{
scanf("%d",&T);
st[0].link=-1;
for(int j=1;j<=T;j++)
{
scanf("%s",s+1);n=strlen(s+1);last=0;
for(int i=1;i<=n;i++)extend(s[i]-'a',j);
}
for(int i=1;i<=id;i++)buildroad(st[i].link,i);
dfs(0);
for(int i=1;i<=T;i++)printf("%d\n",ans[i]);
}