• BZOJ 1030 AC自动机+DP


    题意:给n个长度为m的单词串,问你一段长度为m的文本中包含任一单词串的方案数,对10007取模

    n <= 60, m <= 100

    思路:单词串建个AC自动机,在AC自动机上跑DP

    一共有26^m种方案,减去不包含有单词串的方案就是答案

    设dp[i][j]为第i个字符,在AC自动机上第j个节点的方案数,答案是26^m-sum(dp[m])

    转移就是通过前一个字符的fail指针转移到后一个

    如果前一个状态包含单词串,那么后一个无论是什么都包含

    同样如果有走到结束标记的点也会导致包含

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<queue>
     6 #define LL long long
     7 #define debug(x) cout << "[" << x << "]" << endl
     8 using namespace std;
     9 
    10 const int mx = 6010;
    11 const int mod = 10007;
    12 int ans = 1;
    13 int dp[610][mx];
    14 char s[110];
    15 
    16 struct Trie{
    17     int nxt[mx][26], sum[mx], fail[mx];
    18     int cnt;
    19 
    20     void insert(const char* s){
    21         int u = 0, len = strlen(s);
    22         for (int i = 0; i < len; i++){
    23             int c = s[i]-'A';
    24             if (!nxt[u][c]) nxt[u][c] = ++cnt;
    25             u = nxt[u][c];
    26         }
    27         sum[u] = 1;
    28     }
    29     void build(){
    30         queue<int> q;
    31         for (int i = 0; i < 26; i++)
    32             if (nxt[0][i]) fail[nxt[0][i]] = 0, q.push(nxt[0][i]);
    33         while (!q.empty()){
    34             int u = q.front(); q.pop();
    35             for (int i = 0; i < 26; i++){
    36                 if (nxt[u][i]) fail[nxt[u][i]] = nxt[fail[u]][i], q.push(nxt[u][i]);
    37                 else nxt[u][i] = nxt[fail[u]][i];
    38             }
    39             if (sum[fail[u]]) sum[u] = 1;
    40         }
    41     }
    42     void f(int i){
    43         for (int j = 0; j <= cnt; j++){
    44             if (sum[j] || !dp[i-1][j]) continue;
    45             for (int k = 0; k < 26; k++){
    46                 int c = nxt[j][k];
    47                 dp[i][c] = (dp[i][c]+dp[i-1][j])%mod;
    48             }
    49         }
    50     }
    51 }ac;
    52 
    53 int main(){
    54     int n, m;
    55     scanf("%d%d", &n, &m);
    56     for (int i = 1; i <= n; i++){
    57         scanf("%s", s);
    58         ac.insert(s);
    59     }
    60     ac.build();
    61     dp[0][0] = 1;
    62     for (int i = 1; i <= m; i++) ac.f(i);
    63     for (int i = 1; i <= m; i++) ans = ans*26%mod;
    64     for (int i = 0; i <= ac.cnt; i++)
    65         if (!ac.sum[i]) ans = (ans+mod-dp[m][i])%mod;
    66     printf("%d
    ", ans);
    67     return 0;
    68 }
  • 相关阅读:
    HashMap 和 Hashtable 的区别
    使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
    short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
    io--文件内容的复制
    heap与stack的区别
    序列化与反序列化
    实现反转的方法(reverse)
    final, finally, finalize 的区别
    request.getSession()、reqeust.getSession(false)和request.getSession(true)
    如何优化网页的加载速度
  • 原文地址:https://www.cnblogs.com/QAQorz/p/9750934.html
Copyright © 2020-2023  润新知