• 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 }
  • 相关阅读:
    Android API之android.provider.ContactsContract.Data
    Android API之android.provider.ContactsContract
    Android API之android.provider.ContactsContract.Contacts
    Android API之android.os.Parcelable
    Android网络开发之基本介绍
    wpf小技巧——datagrid 滚动条问题
    C# List去重的三种方法(转)
    spring jwt springboot RESTful API认证方式
    Springboot 实现api校验和登录验证
    SpringBoot系列
  • 原文地址:https://www.cnblogs.com/QAQorz/p/9750934.html
Copyright © 2020-2023  润新知