zoukankan      html  css  js  c++  java
  • BZOJ 1030: [JSOI2007]文本生成器( AC自动机 + dp )

    之前一直没调出来T^T...早上刷牙时无意中就想出错在哪里了...

    对全部单词建AC自动机, 然后在自动机上跑dp, dp(i, j)表示匹配到了第i个字符, 在自动机上的j结点的方案数, 然后枚举A~Z进行转移.

    --------------------------------------------------------------------------

    #include<bits/stdc++.h>
     
    using namespace std;
     
    #define idx(c) ((c) - 'A')
     
    const int maxn = 109;
    const int maxm = 69;
    const int N = 26;
    const int MOD = 10007;
     
    struct Node {
    Node *ch[26], *fail;
    int id;
    bool F;
    } pool[maxn * maxm], *pt = pool, *root = pt++;
     
    int CNT = 0, c = 0, p = 1, tot = 1;
    int n, m, dp[2][maxn * maxm];
    char s[maxn];
     
    inline Node* newNode() {
    pt->fail = root;
    pt->F = false;
    pt->id = CNT++;
    return pt++;
    }
     
    void insert(char* c, int len) {
    Node* t = root;
    for(; len--; c++) {
    if(!t->ch[idx(*c)]) t->ch[idx(*c)] = newNode();
    t = t->ch[idx(*c)];
    }
    t->F = true;
    }
     
    queue<Node*> Q;
    void BFS() {
    for(int i = 0; i < N; i++)
       if(root->ch[i]) Q.push(root->ch[i]);
    while(!Q.empty()) {
    Node* t = Q.front(); Q.pop();
    for(int i = 0; i < N; i++) if(t->ch[i]) {
    Node* o = t->fail;
    while(o != root && !o->ch[i]) o = o->fail;
    t->ch[i]->fail = (o->ch[i] ? o->ch[i] : root);
    if(t->ch[i]->fail->F) t->ch[i]->F = true;
    Q.push(t->ch[i]);
    }
    }
    }
     
    void DFS(Node* t) {
    // if(t->F || !dp[p][t->id]) return; it's wrong
    if(t->F) return;
    for(int i = 0; i < N; i++) if(t->ch[i]) {
    DFS(t->ch[i]);
    dp[c][t->ch[i]->id] += dp[p][t->id];
    if(dp[c][t->ch[i]->id] >= MOD) dp[c][t->ch[i]->id] -= MOD;
    } else {
    Node* o = t->fail;
    while(o != root && !o->ch[i]) o = o->fail;
    int id = (o->ch[i] ? o->ch[i]->id : 0);
       dp[c][id] += dp[p][t->id];
       if(dp[c][id] >= MOD) dp[c][id] -= MOD;
    }
    }
     
    void dfs(Node* t) {
    if(!t->F) {
    tot -= dp[c][t->id];
    if(tot < 0) tot += MOD;
    }
    for(int i = 0; i < N; i++) 
       if(t->ch[i]) dfs(t->ch[i]);
     
    int main() {
    root = newNode(); root->fail = root;
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i++) {
    scanf("%s", s);
    insert(s, strlen(s));
    }
    BFS();
    memset(dp, 0, sizeof dp);
    dp[c][0] = 1;
    for(int i = 0; i < m; i++) {
    (tot *= 26) %= MOD;
    swap(c, p);
    memset(dp[c], 0, sizeof dp[c]);
       DFS(root);
    }
    dfs(root);
    printf("%d ", tot);
    return 0;
    }

    --------------------------------------------------------------------------

    1030: [JSOI2007]文本生成器

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 2679  Solved: 1107
    [Submit][Status][Discuss]

    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

  • 相关阅读:
    ORA00845 MEMORY_TARGET not supported on this system (oracle11g for asianux3 )
    文件处理命令
    网络通信
    Chapter05Usage and Configuration of the Oracle Shared Server
    压缩解压缩命令
    PAT 1088 Rational Arithmetic[模拟分数的加减乘除][难]
    知识点最小二乘学习与正规表达式
    Missing Number[回溯][难]
    PAT 1065 A+B and C[大数运算][溢出]
    PAT 1055 The World's Richest[排序][如何不超时]
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4804044.html
Copyright © 2011-2022 走看看