Description:
1<=n<=10^6,1<=
∑|S|
<=10^6
题解:
不同子串肯定和后缀自动机有关。
对每个串搞出后缀自动机。
关键在于如何合并这些玩意。
倒着做。
设 fx 表示到x状态往后搞的不同串的方案数。
可以枚举它的下一个字符是什么,如果自动机里有边,就可以直接走过去传递。
如果没有,可以找到后面的自动机中第一个root有这个字符的对应的状态,从那里转移。
答案就是所以最后出现的字符的对应状态的f的sum。
Code:
#include<cstdio>
#include<cstring>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;
const int N = 2e6 + 5;
const int mo = 1e9 + 7;
int f[N], lat[26];
struct suffix_automation {
int last, tot, fa[N], to[N][26], dep[N];
#define push(v) dep[++ tot] = v;
void Extend(int st, int c) {
push(dep[last] + 1);
int p = last, np = tot;
for(; p && !to[p][c]; p = fa[p]) to[p][c] = np;
if(!p) fa[np] = st; else {
int q = to[p][c];
if(dep[p] + 1 < dep[q]) {
push(dep[p] + 1);
int nq = tot;
memcpy(to[nq], to[q], sizeof to[q]);
fa[nq] = fa[q]; fa[q] = fa[np] = nq;
for(; to[p][c] == q; p = fa[p]) to[p][c] = nq;
} else fa[np] = q;
}
last = np;
}
int d[N], ff[N], r[N];
void bfs(int x, int y) {
int st = 1, en = 0;
fo(i, x, y)
fo(j, 0, 25) if(to[i][j])
r[to[i][j]] ++;
fo(i, x, y) if(!r[i]) d[++ en] = i;
for(; st <= en; st ++) {
int x = d[st];
fo(j, 0, 25)
if(to[x][j] && !(-- r[to[x][j]])) d[++ en] = to[x][j];
}
fd(i, en, 1) {
int x = d[i];
f[x] = 1;
fo(i, 0, 25) if(to[x][i])
f[x] = (f[x] + f[to[x][i]]) % mo;
else f[x] = (f[x] + f[lat[i]]) % mo;
}
}
} suf;
int n; char s[N];
int st[N], en[N], ans;
int main() {
freopen("str.in", "r", stdin);
freopen("str.out", "w", stdout);
scanf("%d", &n);
fo(i, 1, n) {
scanf("%s", s + 1); int len = strlen(s + 1);
suf.last = suf.tot = st[i] = en[i - 1] + 1;
fo(j, 1, len) suf.Extend(st[i], s[j] - 'a');
en[i] = suf.tot;
}
fd(i, n, 1) {
suf.bfs(st[i], en[i]);
fo(j, 0, 25) if(suf.to[st[i]][j])
lat[j] = suf.to[st[i]][j];
}
fo(k, 0, 25) ans = (ans + f[lat[k]]) % mo;
printf("%d", (ans + 1) % mo);
}