首页 > 代码库 > BZOJ 1030 JSOI 2007 文本生成器 AC自动机+DP

BZOJ 1030 JSOI 2007 文本生成器 AC自动机+DP

题目大意:给出一些字符串。已知如果文章里出现过这些字符串中的一个,那么就说这个文章是可读的。问长度为l的文章有多少是可读的文章。


思路:直接处理不太好弄, 我们可以统计出来不可读的文章,然后用26^l减去就是可读的文章总数。

将所有的字串建Trie图,然后设f[i][j]为文章的第i个字符Trie图中的第j个节点的时候不可读的文章的数量。转移就很简单了。注意一下取模就行了。


CODE:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 10010
#define MO 10007
using namespace std;
#define P(a) ((a) - 'A')
 
struct Trie{
    Trie *son[26],*fail;
    bool end,id;
}mempool[MAX],*C = mempool,*root = C++;
 
int cnt,length;
char s[MAX];
int f[110][MAX];//表示匹配到第i位trie图中j时的种类数。显然f[0][0] = 1;
 
inline void Insert(char *s)
{
    Trie *now = root;
    while(*s != '\0') {
        if(now->son[P(*s)] == NULL)
            now->son[P(*s)] = C++;
        now = now->son[P(*s)];
        ++s;
    }
    now->end = true;
}
 
void BuildTrieGraph()
{
    static queue<Trie *> q;
    while(!q.empty())   q.pop();
    for(int i = 0; i < 26; ++i)
        if(root->son[i] != NULL)
            root->son[i]->fail = root,q.push(root->son[i]);
        else    root->son[i] = root;
    while(!q.empty()) {
        Trie *now = q.front(); q.pop();
        for(int i = 0; i < 26; ++i)
            if(now->son[i] != NULL) {
                now->son[i]->fail = now->fail->son[i];
                now->son[i]->end |= now->fail->son[i]->end;
                q.push(now->son[i]);
            }
            else    now->son[i] = now->fail->son[i] ? now->fail->son[i]:root;
    }
}
 
int main()
{
    cin >> cnt >> length;
    for(int i = 1; i <= cnt; ++i) {
        scanf("%s",s);
        Insert(s);  
    }
    BuildTrieGraph();
    f[0][0] = 1;
    for(int i = 0; i < length; ++i)
        for(int j = 0; j < C - mempool; ++j)
            for(int k = 0; k < 26; ++k) {
                Trie *now = mempool[j].son[k];
                if(!now->end)
                    f[i + 1][now - mempool] = (f[i + 1][now - mempool] + f[i][j]) % MO;
            }
    int ans = 0;
    for(int i = 0; i < C - mempool; ++i)
        ans = (ans + f[length][i]) % MO;
    int total = 1;
    for(int i = 1; i <= length; ++i)
        total = total * 26 % MO;
    cout << (total - ans + MO) % MO << endl;
    return 0;
}


BZOJ 1030 JSOI 2007 文本生成器 AC自动机+DP