【bzoj1030】[JSOI2007]文本生成器 trie图DP

Description

JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版。该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完全随机的。如果一篇文章中至少包含使用者们了解的一个单词,那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串)。但是,即使按照这样的标准,使用者现在使用的GW文本生成器v6版所生成的文章也是几乎完全不可读的。 ZYX需要指出GW文本生成器 v6生成的所有文本中可读文本的数量,以便能够成功获得v7更新版。你能帮助他吗?

Input

输入文件的第一行包含两个正整数,分别是使用者了解的单词总数N (<= 60),GW文本生成器 v6生成的文本固定长度M;以下N行,每一行包含一个使用者了解的单词。 这里所有单词及文本的长度不会超过100,并且只可能包含英文大写字母A..Z  。

Output

一个整数,表示可能的文章总数。只需要知道结果模10007的值。

Sample Input

2 2

A

B

Sample Output

100  

HINT

Source

原来trie图上的dp是这么回事…

补集转化,统计一个都不出现的方案数。

dp[i][j]代表当前文章长度为i,转移到trie图上j号节点的方案,不能走有标记的点。

那样就可以从图上转移了, dp[len][v]+=dp[len1][u] ,当存在一条边< u,v >时。

一开始二维数组开反了,导致溢出结果说我WA…日了狗了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int SZ = 10010;
const int mod = 10007;

int dp[110][SZ];

int ch[SZ][30],sz = 0;
bool val[SZ];


void insert(char s[])
{
    int p = 0;
    int l = strlen(s);
    for(int i = 0;i < l;i ++)
    {
        int c = s[i] - 'A';
        if(!ch[p][c]) ch[p][c] = ++ sz;
        p = ch[p][c];
    }
    val[p] = 1;
}

queue<int> q;
int fail[SZ];

void build_ac()
{
    fail[0] = 0;
    for(int c = 0;c < 26;c ++)
    {
        int u = ch[0][c];
        if(u) { q.push(u); fail[u] = 0; }
    }
    while(q.size())
    {
        int f = q.front(); q.pop();
        for(int c = 0;c < 26;c ++)
        {
            int u = ch[f][c];
            if(!u) { ch[f][c] = ch[fail[f]][c]; continue; }
            q.push(u);
            int v = fail[f];
            fail[u] = ch[v][c];
        }
        val[f] |= val[fail[f]];
    }
}

char s[SZ];

int main()
{
// freopen("1030.in","r",stdin);
// freopen("1030.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++)
    {
        scanf("%s",s);
        insert(s);
    }
    build_ac(); 

    dp[0][0] = 1;
    for(int len = 1;len <= m;len ++)
    {
        for(int u = 0;u <= sz;u ++) 
        {
            if(val[u]) continue;
            for(int c = 0;c < 26;c ++)
            {
                int v = ch[u][c];
                dp[len][v] = (dp[len][v] + dp[len - 1][u]) % mod;
            }
        }
    }
    int ans = 0,tot = 1;
    for(int i = 1;i <= m;i ++) tot = tot * 26 % mod;
    for(int i = 0;i <= sz;i ++)
        if(!val[i])
            ans = (ans + dp[m][i]) % mod;
    printf("%d",(tot - ans + mod) % mod);
    return 0;
}

/* 1 3 BB 51 2 3 AB BC 10 9 SFLLDAZLC HCIW XEOJOMNYV ZY WRFPUP DHWAI SLQADOOK A CYBOIE N */

你可能感兴趣的:(【bzoj1030】[JSOI2007]文本生成器 trie图DP)