• URAL 1158 AC自动机上的简单DP+大数


     题目大意

    在一种语言中的字母表中有N(N<=50)个字母,每个单词都由M(M<=50)个字母构成,因此,一共可以形成N^M个单词。但是有P(P<=10)个串是被禁止的,也就是说,任何单词的子串都不能包含这P个串中的任意一个。问按照上述规则,能产生的合法串一共有多少个? 例如:N=3 M=3 P=3 字母表中的三个字符是QWE 被禁止的串为”QQ”,”WEE”,”Q”,则合法的串一共有7个。

    这题目相当于通过步数对AC自动机上每一个点的状态进行DP

    dp[i][j]表示到达i这个点,走了j步存在多少种方法

    总是从上一步推到下一步

    写成滚动数组也不会有问题

    这里要注意在AC自动机更新操作时,要将每个串末尾能到达的fail位置也记上标记,题解中有注释解释

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <queue>
      4 #include <vector>
      5 #include <iostream>
      6 #include <algorithm>
      7 #include <map>
      8 using namespace std;
      9 #define clr(x) memset(x , 0 , sizeof(x))
     10 #define set(x) memset(x , -1 , sizeof(x))
     11 typedef long long LL ;
     12 #define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )
     13 #define For( i , a , b ) for ( int i = a ; i <= b ; ++ i )
     14 #define rev( i , a , b ) for ( int i = a ; i >= b ; -- i )
     15 map<char , int> mp;
     16 
     17 const int CHAR_SIZE = 51;
     18 const int MAX_SIZE = 105;
     19 const int M = 10000 ;
     20  int n,m,p;
     21 
     22 struct BigInt {
     23     int wei , a[100];
     24     BigInt(){
     25         wei = 1;
     26         memset(a , 0 , sizeof(a));
     27     }
     28     void init(){
     29         wei = 1;
     30         memset(a , 0 , sizeof(a));
     31     }
     32     void print(){
     33         for(int i=wei-1 ; i>=0 ; i--) printf("%d" , a[i]);
     34         printf("
    ");
     35     }
     36     BigInt operator+(BigInt m){
     37         BigInt ret;
     38         int ma = max(wei , m.wei);
     39         for(int i=0 ; i<ma ; i++){
     40             ret.a[i] += a[i]+m.a[i];
     41             if(ret.a[i]>=10) ret.a[i+1]++,ret.a[i]-=10;
     42         }
     43         if(ret.a[ma]) ret.wei = ma+1;
     44         else ret.wei = ma;
     45         return ret;
     46     }
     47 };
     48 
     49 struct AC_Machine{
     50     int ch[MAX_SIZE][CHAR_SIZE] , val[MAX_SIZE] , fail[MAX_SIZE];
     51     int sz;
     52 
     53     void init(){
     54         sz = 1;
     55         clr(ch[0]) , clr(val);
     56     }
     57 
     58     void insert(char *s){
     59         int n = strlen(s);
     60         int u=0 ;
     61         for(int i=0 ; i<n ; i++){
     62             int c = mp[s[i]];
     63             if(!ch[u][c]){
     64                 clr(ch[sz]);
     65                 val[sz] = 0;
     66                 ch[u][c] = sz++;
     67             }
     68             u = ch[u][c];
     69         }
     70         val[u] = 1;
     71     }
     72 
     73     void get_fail(){
     74         queue<int> Q;
     75         fail[0] = 0;
     76         for(int c=0 ; c<n ; c++){
     77             int u = ch[0][c];
     78             if(u){Q.push(u);fail[u]=0;}
     79         }
     80         while(!Q.empty()){
     81             int r = Q.front();
     82             Q.pop();
     83             //比如is, history都是非法的,history中有is,那么history访问到它的s时也是非法的
     84             val[r] |= val[fail[r]];
     85             for(int c=0 ; c<n ; c++){
     86                 int u = ch[r][c];
     87                 if(!u){ch[r][c] = ch[fail[r]][c]; continue;}
     88                 fail[u] = ch[fail[r]][c];
     89                 Q.push(u);
     90             }
     91         }
     92     }
     93 }ac;
     94 
     95 char str[155];
     96 BigInt dp[MAX_SIZE][155];
     97 
     98 BigInt solve(int n , int step)
     99 {
    100     for(int i=0 ; i<ac.sz ; i++)
    101         for(int j=0 ; j<=step ; j++){
    102                 dp[i][j].init();
    103         }
    104     dp[0][0].wei = dp[0][0].a[0] = 1;
    105     for(int i=1 ; i<=step ; i++){
    106         for(int j=0 ; j<ac.sz ; j++){
    107             for(int k=0 ; k<n ; k++)
    108                 if(!ac.val[ac.ch[j][k]]){
    109                     dp[ac.ch[j][k]][i] = dp[ac.ch[j][k]][i]+dp[j][i-1];
    110                 }
    111         }
    112     }
    113     BigInt ret = BigInt();
    114     for(int j=0 ; j<ac.sz ; j++) ret = ret+dp[j][step];
    115     return ret;
    116 }
    117 
    118 int main()
    119 {
    120    // freopen("in.txt" , "r" , stdin);
    121    // freopen("out.txt" , "w" , stdout);
    122     while(~scanf("%d%d%d" , &n , &m , &p)){
    123         mp.clear();
    124         getchar();
    125         gets(str);
    126         for(int i=0 ; i<strlen(str) ; i++) mp[str[i]] = i;
    127         ac.init();
    128         for(int i=1 ; i<=p ; i++){
    129             gets(str);
    130             ac.insert(str);
    131         }
    132         ac.get_fail();
    133         BigInt ret = solve(n , m);
    134         ret.print();
    135     }
    136     return 0;
    137 }
  • 相关阅读:
    C++实现高斯滤波器
    移动通信
    最简单的DLL
    C/C++ 编译和链接过程
    Servlet 详解
    对 Java 集合的巧妙利用
    Java 泛型
    Java 字符编码与解码
    HTTP 400 错误
    a 标签的四种样式
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4738180.html
Copyright © 2020-2023  润新知