题意:
给你一个字典,还有一些非法串,利用字典中的字符组成长度为m的不含非法串的字符串,求方案数。
解法:
坑了我一整天我擦。。。。
因为自动机本身就是一个状态转移图,所以在上面进行DP很好理解,dp[i][j]记录长度为i并且走到DFA中j节点的方案数。。
需要注意的是非法节点是不能走的,在建Trie图的时候也要注意,如果当前节点的fail节点是非法的,那么这个点也是非法的,因为这个串包含了某个非法串。。。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<map> 5 #include<algorithm> 6 using namespace std; 7 const int base = 10; 8 const int N = 105; 9 struct BigInt{ 10 int v[N],len; 11 BigInt(int r = 0){ 12 memset(v,0,sizeof(v)); 13 for(len = 0;r > 0;r /= base)v[len++] = r % base; 14 } 15 BigInt operator + (const BigInt &a){ 16 BigInt ans;int i ,c = 0; 17 for(i = 0;i < len || i < a.len || c > 0;i++){ 18 if(i < len)c += v[i]; 19 if(i < a.len)c += a.v[i]; 20 ans.v[i] = c % base;c /= base; 21 } 22 ans.len = i; 23 return ans; 24 } 25 void print(){ 26 printf("%d",len==0?0:v[len - 1]); 27 for(int i = len - 2;i >= 0;i--) 28 printf("%d",v[i]); 29 puts(""); 30 } 31 }; 32 BigInt dp[55][N]; 33 34 struct node{ 35 node *ch[55],*fail; 36 bool flag; 37 void clear(){ 38 for(int i = 0;i < 55;i++)ch[i] = NULL;fail = NULL; 39 flag = 0; 40 } 41 }; 42 map<char,int>hash; 43 node stk[N*6]; 44 struct Trie{ 45 node *root;int top,sz; 46 node* newnode(){ 47 node *p = &stk[top++]; 48 p -> clear(); 49 return p; 50 } 51 void init(int size){ 52 top = 0; 53 sz = size; 54 root = newnode(); 55 } 56 void insert(char *s){ 57 node *p = root;int len = strlen(s); 58 for(int i = 0 ;i < len;i++){ 59 int id = hash[s[i]]; 60 if(p -> ch[id] == NULL) 61 p -> ch[id] = newnode(); 62 p = p -> ch[id]; 63 } 64 p -> flag = 1; 65 } 66 void build(){ 67 queue<node*> Q; 68 root -> fail = root; 69 for(int i = 0;i < sz;i++) 70 if(root -> ch[i] == NULL) 71 root -> ch[i] = root; 72 else{ 73 Q.push(root -> ch[i]); 74 root -> ch[i] -> fail = root; 75 } 76 while(!Q.empty()){ 77 node *p = Q.front();Q.pop(); 78 for(int i = 0;i < sz;i++) 79 if(p -> ch[i] == NULL) 80 p -> ch[i] = p -> fail -> ch[i]; 81 else{ 82 Q.push(p -> ch[i]); 83 p -> ch[i] -> fail = p -> fail -> ch[i]; 84 p -> ch[i] -> flag |= p -> ch[i] -> fail -> flag; 85 } 86 } 87 } 88 void solve(int len){ 89 for(int i = 0;i < 55;i++) 90 for(int j = 0;j < top;j++) 91 dp[i][j] = BigInt(); 92 dp[0][root - stk] = BigInt(1); 93 for(int i = 0;i < len;i++) 94 for(int j = 0;j < top;j++){ 95 node *cur = &stk[j]; 96 if(cur -> flag)continue; 97 for(int k = 0;k < sz;k++){ 98 node *next = cur -> ch[k]; 99 if(next -> flag)continue; 100 dp[i+1][next - stk] = dp[i+1][next - stk] + dp[i][j]; 101 } 102 } 103 BigInt ans; 104 for(int i = 0;i < top;i++) 105 ans = ans + dp[len][i]; 106 ans.print(); 107 } 108 }; 109 Trie AC; 110 char s[N]; 111 int main(){ 112 int n,m,p; 113 while(~scanf("%d%d%d",&n,&m,&p)){ 114 scanf("%s",s);int len = strlen(s); 115 hash.clear(); 116 for(int i = 0;i < len;i++) 117 hash[s[i]] = i; 118 AC.init(n); 119 for(int i = 0;i < p;i++){ 120 scanf("%s",s); 121 AC.insert(s); 122 } 123 AC.build(); 124 AC.solve(m); 125 } 126 return 0; 127 }