2018 Tenth Sichuan Province, Race C: Clannad [AC automaton + dp]

topic:

Topic Link ~~~

Meaning of the questions:

After each segment of the substring given M, ask how many letter string division manner, such that M is a sub-division string

analysis:

The question how many each prefix requires division manner, readily occur recursive definition DP [i] denotes the i-th prefix end how many division manner, the transfer is not difficult, it is assumed that the suffix letter string matching prefix a substring of length len, the dp [i] + = dp [i-len], to quickly find all matching substring just hit AC automatic machine, to use this last optimization, i.e. a pointer to fail node can match the success of the jump

Code:

#include <bits/stdc++.h>
 
using namespace std;
typedef long long LL;
const int MAXN = 1e5+25;
const LL mod = 1e9+7;
char s[MAXN],ss[MAXN];
int tire[MAXN][26],num[MAXN],fail[MAXN],last[MAXN],dp[MAXN],cnt,t,n,m;
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
inline void init(int x)
{
    for(int i = 0;i < 26; ++i) tire[x][i] = 0;
    num[x] = 0;
    last[x] = 0;
}
void Build_ac(char *s)
{
    int root = 0,len = strlen(s),t;
    for(int i = 0;i < len; ++i){
        t = s[i] - 'a';
        if(!tire[root][t]){
            tire[root][t] = ++cnt;
            init(cnt);
        }
        root = tire[root][t];
    }
    num[root] = len;
}
void Get_fail()
{
    queue<int> p;
    for(int i = 0; i < 26; ++i){
        int son = tire[0][i];
        if(son){
            fail[son] = 0;
            p.push(son);
        }
        else tire[0][i] = 0;
    }
    while(!p.empty())
    {
        int x = p.front();p.pop();
        for(int i = 0; i < 26; ++i){
            if(tire[x][i]){
                int son = tire[x][i];
                fail[son] = tire[fail[x]][i];
                p.push(son);
                if(num[fail[son]]) last[son] = fail[son];
                else last[son] = last[fail[son]];
            }
            else tire[x][i] = tire[fail[x]][i];
        }
    }
}
void Query_ac(char *s)
{ 
    int root = 0,len = strlen(s);
    for(int i = 0;i < len; ++i){
        LL ans = 0;
        root = tire[root][s[i]-'a'];
        for(int j = root; j ; j = last[j]){
            if(!num[j]) continue;
            ans += dp[i+1-num[j]];
            if(ans >= mod) ans -= mod;
        }
        dp[i+1] = ans%mod;
    }
}
int main()
{
    scanf("%d",&t);
    dp[0] = 1;
    while(t--)
    {
        init(0);cnt = 0;
        scanf("%d %d",&n,&m);
        scanf("%s",ss);
        while(m--){
            scanf("%s",s);
            Build_ac(s);
        }
        Get_fail(); Query_ac(ss);
        for(int i = 1;i < n; ++i) write(dp[i]),putchar(' ');
        printf("%d\n",dp[n]);
    }
    return 0;
}

 

Guess you like

Origin blog.csdn.net/qq_41157137/article/details/92185684