1. 程式人生 > >[Luogu P4052] [BZOJ 1030] [JSOI2007]文字生成器

[Luogu P4052] [BZOJ 1030] [JSOI2007]文字生成器

洛谷傳送門

BZOJ傳送門

題目描述

JSOI交給隊員ZYX一個任務,編制一個稱之為“文字生成器”的電腦軟體:該軟體的使用者是一些低幼人群,他們現在使用的是GW文字生成器v6版。

該軟體可以隨機生成一些文章―――總是生成一篇長度固定且完全隨機的文章—— 也就是說,生成的文章中每個位元組都是完全隨機的。如果一篇文章中至少包含使用者們瞭解的一個單詞,那麼我們說這篇文章是可讀的(我們稱文章a包含單詞b,當且僅當單詞b是文章a的子串)。但是,即使按照這樣的標準,使用者現在使用的GW文字生成器v6版所生成的文章也是幾乎完全不可讀的?。ZYX需要指出GW文字生成器 v6

生成的所有文字中可讀文字的數量,以便能夠成功獲得v7更新版。你能幫助嗎?

輸入輸出格式

輸入格式:

輸入檔案的第一行包含兩個正整數,分別是使用者瞭解的單詞總數 N ( 60 ) N (\le 60) ,GW文字生成器 v6生成的文字固定長度 M

M ;以下N行,每一行包含一個使用者瞭解的單詞。這裡所有單詞及文字的長度不會超過 100 100 ,並且只可能包含英文大寫字母 A . .
. Z A...Z

輸出格式:

一個整數,表示可能的文章總數。只需要知道結果模 10007 10007 的值。

輸入輸出樣例

輸入樣例#1:

2 2
A
B

輸出樣例#1:

100

解題分析

A C AC 自動機上 d p dp , 求出沒有給定字串的個數, 再用 2 6 m 26^m 去減就好了。

程式碼如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#include <queue>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MOD 10007
#define MX 10050
int son[MX][26], fail[MX];
std::queue <int> q;
bool tag[MX];
char buf[MX];
int dp[105][MX];
int cnt, root, n, num;
IN int fpow(R int base, R int tim)
{
    int ret = 1; base %= MOD;
    W (tim)
    {
        if (tim & 1) ret = 1ll * ret * base % MOD;
        base = 1ll * base * base % MOD, tim >>= 1;
    }
    return ret;
}
IN void add(R int ad, int &tar) {tar += ad; if (tar >= MOD) tar -= MOD;}
void insert()
{
    R int len = std::strlen(buf), now = root, id;
    for (R int i = 0; i < len; ++i)
    {
        id = buf[i] - 'A';
        if (!son[now][id]) son[now][id] = ++cnt;
        now = son[now][id];
    }
    tag[now] = true;
}
void build()
{
    R int now = root, tar;
    for (R int i = 0; i < 26; ++i) if (son[now][i]) q.push(son[now][i]);
    W (!q.empty())
    {
        now = q.front(); q.pop();
        for (R int i = 0; i < 26; ++i)
        {
            if (son[now][i])
            {
                fail[son[now][i]] = son[fail[now]][i];
                tag[son[now][i]] |= tag[fail[son[now][i]]];
                q.push(son[now][i]);
            }
            else son[now][i] = son[fail[now]][i];
        }
    }
}
void DP()
{
    R int i, j, k, nex;
    dp[0][0] = 1;
    for (i = 0; i < n; ++i)
    {
        nex = i + 1;
        for (j = 0; j <= cnt; ++j)
        for (k = 0; k < 26; ++k)
        if (!tag[son[j][k]]) add(dp[i][j], dp[nex][son[j][k]]);
    }
    int ans = 0;
    for (i = 0; i <= cnt; ++i) add(dp[n][i], ans);
    printf("%d", (fpow(26, n) - ans + MOD) % MOD);
}
int main(void)
{
    scanf("%d%d", &num, &n);
    W (num--) scanf("%s", buf), insert();
    build(); DP();
}