【NOI2017模拟6.2】字符串

来源:互联网 发布:卡是3g的手机是2g网络 编辑:程序博客网 时间:2024/05/14 23:05

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);}