题目链接
题目解法
题目的意思是有很多字符串,问依次把每个串的子串拼起来有多少种不同的字符串
子串问题可以想到用
S
A
M
SAM
SAM
考虑对于每个字符串建立单独的
S
A
M
SAM
SAM
现在需要考虑如何将串联系起来
考虑
2
2
2 种相同的拼法
“
a
b
c
”
+
“”
“abc”+“”
“abc”+“”,
“
a
b
”
+
“
c
”
“ab”+“c”
“ab”+“c”,我们可以想到规定每个串必须选到最长在到下一个串,这样就不会重复
体现在
S
A
M
SAM
SAM 上就是再一个单独的
S
A
M
SAM
SAM 中走到头不能走了,再换到下一个
S
A
M
SAM
SAM 继续走
所以我们可以建立一些新指针,如
u
u
u 不能通过
c
c
c 继续走了,那么把
c
h
[
u
]
[
c
]
ch[u][c]
ch[u][c] 变成
c
h
[
下一个
S
A
M
的根
]
[
c
]
ch[下一个SAM的根][c]
ch[下一个SAM的根][c]
然后按照普通 S A M SAM SAM 统计子串的个数就可以了
#include <bits/stdc++.h>
using namespace std;
const int N(2000100),P(1e9+7);
struct Node{
int len,fa,ch[26];
}node[N];
int n,m,root[N],dp[N],last,tot;
char str[N];
bool vis[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void dfs(int u,int rt2){
if(vis[u]) return;
vis[u]=1;
for(int i=0;i<26;i++)
if(node[u].ch[i]) dfs(node[u].ch[i],rt2);
else vis[node[u].ch[i]=node[rt2].ch[i]]=1;
}
int calc(int u){
if(dp[u]) return dp[u];
dp[u]=1;
for(int i=0;i<26;i++) if(node[u].ch[i]) (dp[u]+=calc(node[u].ch[i]))%=P;
return dp[u];
}
void extend(int c,int rt){
int p=last,np=last=++tot;node[np].len=node[p].len+1;
for(;p&&!node[p].ch[c];p=node[p].fa) node[p].ch[c]=np;
if(!p) node[np].fa=rt;
else{
int q=node[p].ch[c];
if(node[q].len==node[p].len+1) node[np].fa=q;
else{
int nq=++tot;node[nq]=node[q],node[nq].len=node[p].len+1;
node[np].fa=node[q].fa=nq;
for(;p&&node[p].ch[c]==q;p=node[p].fa) node[p].ch[c]=nq;
}
}
}
int main(){
n=read();
for(int i=1;i<=n;i++){
scanf("%s",str+1);
root[i]=last=++tot;
int len=strlen(str+1);
for(int j=1;j<=len;j++) extend(str[j]-'a',root[i]);
}
for(int i=n-1;i>=1;i--) dfs(root[i],root[i+1]);
printf("%d",calc(root[1]));
return 0;
}