bzoj1030

AC自动机和DP。

f[i][j] 表示在匹配到第i位置,处于ac自动机的j节点。决策第(i+1)个字母,计算出转移到第j2节点。

f[i+1][j2] += f[i][j];

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxl = 100 + 10;
const int maxn = 6000;
const int MOD = 10007;

char s[maxl];
int a[maxn][26],q[maxn],next[maxn];
int f[maxl][maxn];
bool flag[maxn];
int n,m,cnt=1;

void insert(char s[]) {
    int cur = 1,len = strlen(s);
    for(int i = 0,c; i < len;i++) {
        c = s[i] - 'A';
        if(a[cur][c]) cur = a[cur][c];
        else cur = a[cur][c] = ++cnt;
    }
    flag[cur] = 1;
}

void AC_automaton() {
    int l=0,r=0,cur;
    q[r++] = 1,next[1] = 0;
    while(l < r) {
        cur = q[l++];
        for(int i=0,k;i<26;i++)
            if(a[cur][i]) {
                k = next[cur];
                while(!a[k][i]) k = next[k];
                next[a[cur][i]] = a[k][i];
                if(flag[a[k][i]]) flag[a[cur][i]]= 1;
                q[r++] = a[cur][i];
            }
    }
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i = 0; i < 26; i++)
        a[0][i] = 1;
    for(int i = 1; i <= n; i++) 
        scanf("%s",s),insert(s);
    AC_automaton();
    f[0][1] = 1;
    for(int i = 1; i <= m; i++) {
        for(int j = 1; j <= cnt; j++)
            if(!flag[j] && f[i-1][j])  
                for(int k = 0; k < 26; k++) {
                    int cur = j;
                    while(!a[cur][k]) cur = next[cur];
                    f[i][a[cur][k]] = (f[i][a[cur][k]]+f[i-1][j])%MOD; 
                }
    }
    int res1=1,res2=0;
    for(int i = 1; i <= m; i++) res1 = (res1*26)%MOD;
    for(int i = 1; i <= cnt; i++) if(!flag[i])
        res2 = (res2+f[m][i])%MOD; 
    printf("%d\n",(res1-res2+MOD)%MOD); 
    return 0;
}
posted @ 2016-04-15 20:17  invoid  阅读(244)  评论(0编辑  收藏  举报