题目大意
在一种语言中的字母表中有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 }