AC自动机+状态压缩DP。用dp[i][j][k]表示走i步,到达AC自动机中的j节点,含有的字符串k种类(二进制状态压缩),所有的方案数。
#include <iostream> #include <sstream> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <map> #include <set> #include <bitset> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <climits> #define maxn 105 #define eps 1e-6 #define mod 20090717 #define INF 99999999 #define lowbit(x) (x&(-x)) //#define lson o<<1, L, mid //#define rson o<<1 | 1, mid+1, R typedef long long LL; typedef unsigned long long ULL; using namespace std; struct node { int next[maxn][26]; int fail[maxn]; int end[maxn]; char s[maxn]; queue<int> q; int top, now, root; int newnode(void) { end[top] = 0; fail[top] = -1; for(int i = 0; i < 26; i++) next[top][i] = -1; return top++; } void init(void) { top = 0; root = newnode(); } void insert(int x) { int i, len = strlen(s), k; now = root; for(i = 0; i < len; i++) { k = s[i] - 'a'; if(next[now][k] == -1) next[now][k] = newnode(); now = next[now][k]; } end[now] = x; } void build(void) { int i; fail[root] = root; now = root; for(i = 0; i < 26; i++) if(next[now][i] == -1) next[now][i] = root; else { fail[next[now][i]] = root; q.push(next[now][i]); } while(!q.empty()) { now = q.front(); q.pop(); end[now] |= end[fail[now]]; for(i = 0; i < 26; i++) if(next[now][i] == -1) next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; q.push(next[now][i]); } } } }trie; int dp[30][105][1100]; int is[1100]; int n, m, kk; void read(void) { int i, tmp = 1; trie.init(); for(i = 1; i <= m; i++) { scanf("%s", trie.s); trie.insert(tmp); tmp<<=1; } trie.build(); } void init(void) { memset(dp, 0, sizeof dp); } void work(void) { int o = 0, i, j, k, ans, tmp, res, cnt, p; for(i = 0; i < m; i++) o<<=1, o+=1; dp[0][0][0] = 1; for(i = 0; i <= n; i++) for(j = 0; j < trie.top; j++) for(k = 0; k <= o; k++) { if(dp[i][j][k] == 0) continue; for(p = 0; p < 26; p++) dp[i+1][trie.next[j][p]][k|trie.end[trie.next[j][p]]] = (dp[i+1][trie.next[j][p]][k|trie.end[trie.next[j][p]]] + dp[i][j][k])%mod; } ans = 0; cnt = 0; for(i = 0; i <= o; i++) { tmp = i; res = 0; while(tmp) res+=tmp&1, tmp>>=1; if(res >= kk) is[cnt++] = i; } for(i = 0; i < trie.top; i++) for(j = 0; j < cnt; j++) ans = (ans + dp[n][i][is[j]])%mod; printf("%d\n", ans); } int main(void) { while(scanf("%d%d%d", &n, &m, &kk), n!=0 || m!=0 || kk!=0) { init(); read(); work(); } return 0; }
#include <iostream> #include <sstream> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <map> #include <set> #include <bitset> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <climits> #define maxn 105 #define eps 1e-6 #define mod 20090717 #define INF 99999999 #define lowbit(x) (x&(-x)) //#define lson o<<1, L, mid //#define rson o<<1 | 1, mid+1, R typedef long long LL; typedef unsigned long long ULL; using namespace std; int next[maxn][26]; int fail[maxn]; int end[maxn]; char s[maxn]; int dp[30][105][1100]; int hash[1100]; int n, m, kk; queue<int> q; int top, now, root; int newnode(void) { end[top] = 0; fail[top] = -1; for(int i = 0; i < 26; i++) next[top][i] = -1; return top++; } void init(void) { top = 0; root = newnode(); } void insert(int x) { int i, len = strlen(s), k; now = root; for(i = 0; i < len; i++) { k = s[i] - 'a'; if(next[now][k] == -1) next[now][k] = newnode(); now = next[now][k]; } end[now] = x; } void build(void) { int i; fail[root] = root; now = root; for(i = 0; i < 26; i++) if(next[now][i] == -1) next[now][i] = root; else { fail[next[now][i]] = root; q.push(next[now][i]); } while(!q.empty()) { now = q.front(); q.pop(); end[now] |= end[fail[now]]; for(i = 0; i < 26; i++) if(next[now][i] == -1) next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; q.push(next[now][i]); } } } void read(void) { int i, tmp = 1; for(i = 1; i <= m; i++) { scanf("%s", s); insert(tmp); tmp<<=1; } build(); } void work(void) { int o = 0, i, j, k, ans, p; for(i = 0; i < m; i++) o<<=1, o+=1; for(i = 0; i <= n; i++) for(j = 0; j < top; j++) for(k = 0; k <= o; k++) dp[i][j][k] =0; dp[0][0][0] = 1; for(i = 0; i < n; i++) for(j = 0; j < top; j++) for(k = 0; k <= o; k++) { if(dp[i][j][k] == 0) continue; for(p = 0; p < 26; p++) dp[i+1][next[j][p]][k|end[next[j][p]]] = (dp[i+1][next[j][p]][k|end[next[j][p]]] + dp[i][j][k])%mod; } ans = 0; for(i = 0; i <= o; i++) if(hash[i] >= kk) for(j = 0; j < top; j++) ans = (ans + dp[n][j][i])%mod; printf("%d\n", ans); } int main(void) { int i, j; for(i = 0; i < (1<<10); i++) { hash[i] = 0; for(j = 0; j < 10; j++) if(i & (1<<j)) hash[i]++; } while(scanf("%d%d%d", &n, &m, &kk), n!=0 || m!=0 || kk!=0) { init(); read(); work(); } return 0; }