BZOJ1030 - DP on AC Automata

Description
JSOI gave team member ZYX a task to compile a computer software called "text generator": the users of this software are some young people, and they are now using the GW text generator v6 version. The software can randomly generate some articles -- always a fixed-length and completely random article -- that is, every byte in the generated article is completely random. An article is said to be readable if it contains at least one word known to users (we say article a contains word b if and only if word b is a substring of article a). However, even by such standards, the articles generated by the v6 version of GW Text Generator that users are currently using are almost completely unreadable?. ZYX needs to indicate the amount of readable text out of all the text generated by GW Text Generator v6 in order to be able to successfully get the v7 update. Can you help him?
Input

  The first line of the input file contains two positive integers, which are the total number of words known by the user N (<= 60), and the text generated by the GW text generator v6 has a fixed length M; the following N lines, each containing a user-known word words. All words and text here will be no longer than 100 and may only contain English capital letters A..Z

Output

  An integer representing the total number of possible articles. Just know the value modulo 10007 of the result.

Sample Input

2 2

A

B
Sample Output

100


The meaning of the question is to give some strings, find the total number of strings of length m that contain some strings.
We can think of it the other way around, there are 26^m possibilities for a string of length m, and if we subtract the number of strings that do not contain any given string, the number that remains is the required answer.
So we can first build an AC automaton with all the given strings and then do DP.
We set dp[i][j] to denote the value of dp to a string of length i at node j of the AC automaton. We can clearly know that we want to move from dp[i][j] to dp[i+1][p], where p is the next position. We enumerate k as the 26 characters of A~Z, and find it on the AC automaton. If we jump from j to fail[j], we can jump to some nodes, and there is a substring ending with this node, which means dp[ i+1][j] is not feasible, because doing so will make the given string appear in the final string. If there is no such point, just add dp[i+1][next[j][k]] to dp[i][j], and directly change j to next[j][k].
Finally find 26^m with fast exponentiation, then subtract ∑dp[m][x] (x is all points on the AC automaton).
#include<bits/stdc++.h>
#define md 10007
using namespace std;
int read(){
    char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int n,m,cnt,q[10000],dp[105][10000],ans,tot;
string s;
struct node{
    int sum,fail,next[26];
}F[10000];
int pows(int a,int b){
    int base=1;
    while(b){
        if(b&1) base=base*a%md;
        a=a*a%md;b/=2;
    }
    return base%md;
}
void build(string s){
    int pl=0;
    for(int i=0;i<s.length();i++){
        if(F[pl].next[s[i]-'A']) pl=F[pl].next[s[i]-'A'];
        else{
            cnt++;F[pl].next[s[i]-'A']=cnt;pl=cnt;
        }
    }
    F[pl].sum++;
}
void fail(){
    int h=0,t=0;
    for(int i=0;i<26;i++) if(F[0].next[i]) F[q[++t]=F[0].next[i]].fail=0;
    while(h<t){
        int now=q[++h];
        for(int i=0;i<26;i++)
         if(F[now].next[i]) F[q[++t]=F[now].next[i]].fail=F[F[now].fail].next[i];
         else F[now].next[i]=F[F[now].fail].next[i];
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++){
        cin>>s;build(s);
    }
    fail();
    dp[0][0]=1;
    for(int i=0;i<m;i++)
     for(int j=0;j<=cnt;j++){
        if(!dp[i][j]) continue;
        for(int k=0;k<26;k++){
            int now=j,flag=0,re=0;
            while(!(re&&!now)){
                if(!now) re=1;
                if(F[F[now].next[k]].sum){flag=1;break;}
                now=F[now].fail;
             }
            if(flag) continue;
            now=j;now=F[now].next[k];
            dp[i+1][now]=(dp[i+1][now]+dp[i][j])%md;
         }
     }
    tot=pows(26,m);
    for(int i=0;i<=cnt;i++) 
      ans=(ans+dp[m][i])%md;
    printf("%d",(tot-ans+md)%md);
    return 0;
}

Guess you like

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