题目大意

在一种语言中的字母表中有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("\n");
 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 }

 

 posted on 2015-08-18 00:31  Love风吟  阅读(250)  评论(0编辑  收藏  举报