[JSOI2007] Text generator DP+AC automata

Description
randomly generates an article, if an article contains at least one word that users understand, then we say the article is readable (we say article a contains word b if and only if word b is article a substring).
Now, given the N words that your user knows, randomly generate articles of length M, and find out how many articles are readable.


Sample Input
2 2
A
B


Sample Output
100


This is a good question. . .
Considering DP first, let f[i][j] be the number of readable articles up to the i-th position matching the position numbered j on the AC machine.
For state f[i-1][j] consider what state it can update.
For the current i, j, enumerate 1~26 once, skip fail for each character, and skip to the inheritable position gg.
Then the DP equation can be obtained as: f[i][gg]+=f[i-1][j].


#include <cstdio>
#include <cstring>

using namespace std;
int _max(int x, int y) {return x > y ? x : y;}
const int maxn = 110;
const int mod = 10007;

struct node {
    int fail, v[30];
    node() {memset(v, -1, sizeof(v));}
} t[maxn * 60]; int cnt, list[maxn * 60];
int cc[maxn * 60], f[maxn][60 * maxn];
char ss[maxn];

void bt() {
    int x = 0;
    int len = strlen(ss + 1);
    for(int i = 1; i <= len; i++) {
        int y = ss[i] - 'A' + 1;
        if(t[x].v[y] == -1) t[x].v[y] = ++cnt;
        x = t[x].v[y];
    }
    cc[x] = 1;
}

void get_fail() {
    int head = 1, tail = 2;
    list[1] = 0;
    while(head != tail) {
        int x = list[head];
        for(int i = 1; i <= 26; i++) {
            int y = t[x].v[i];
            if(y == -1) continue;
            if(x == 0) t[y].fail = 0;
            else {
                int j = t[x].fail;
                while(j && t[j].v[i] == -1) j = t[j].fail;
                t[y].fail = _max(0, t[j].v[i]);
            }
            list[tail++] = y;
        }
        if(cc[t[x].fail]) cc[x] = 1;
        head++;
    }
}

int main() {
    int n, m; scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) {
        scanf("%s", ss + 1);
        bt();
    }
    get_fail();
    f[0][0] = 1;
    int kk = 1;
    for(int i = 1; i <= m; i++) {
        (kk *= 26) %= mod;
        for(int j = 0; j <= cnt; j++) {
            if(cc[j] || !f[i - 1][j]) continue;
            for(int k = 1; k <= 26; k++) {
                int u = j;
                while(u && t[u].v[k] == -1) u = t[u].fail;
                if(t[u].v[k] == -1) (f[i][0] += f[i - 1][j]) %= mod;
                else (f[i][t[u].v[k]] += f[i - 1][j]) %= mod;
            }
        }
    }
    int ans = 0;
    for(int i = 0; i <= cnt; i++) if(!cc[i]) (ans += f[m][i]) %= mod;
    (ans = kk - ans) %= mod;
    printf("%d\n", (ans + mod) % mod);
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324952859&siteId=291194637