问题描述:给定m个模式串,计数包含所有模式串且长度为n的字符串的数目。
数据范围:模式串长度不超过10,m <= 10, n <= 25,此外保证答案不超过1015。
分析:既然要计数给定长度且满足给定条件的字符串的数目,自然想到搜索,通过枚举每一位的字符缩减问题规模。这里有两个问题:
(1)枚举代价太高,最坏情况下需要2526次操作。
(2)先枚举出完整串再验证其是否满足条件效率太低。
通过观察,我们发现若完整字符串合法,那么在字符串构造时,每个模式串的前缀作为原串的后缀出现。为此我们考虑在搜索字符串时,
记录字符串的后缀信息,这里存储的后缀应该足够长使得若原串的某个后缀能够匹配某模式串的前缀,那么我们记录的后缀的后缀也能够
匹配。
考虑将所有模式串构造成一颗trie树,考虑trie上的状态转移:nex[i][j]表示编号为i的前缀(节点)在其后拼接上字符'a' + j后所得的串
的后缀在trie中能够匹配的最长的前缀节点编号。
并且用state[i]表示从trie根到i节点构成的串的所有后缀能够匹配模式串的集合。
我们用dp[u][S][l]标识当前枚举原字符串的第i个字符,在此之前已经匹配的模式串集合为S,当前串的后缀能够匹配trie中最深的节点编号为l,
那么可以更新dp:
for each i in 'a' to 'z':
next_pointer = nex[l][i]
dp[u][S][l] += dp[u + 1][S | state[next_pointer]][next_pointer]
通过使用动态规划可以解决问题(1),由于状态不超过26 * 210 * 102,且状态转移代价为26,因此总复杂度不超过2602* 210。
后缀实现对整棵trie的前缀匹配,这点类似于AC自动机,实现的同样是单文本串对多模式串的匹配。

1 #include <algorithm> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <queue> 6 #include <map> 7 #include <set> 8 #include <ctime> 9 #include <cmath> 10 #include <iostream> 11 #include <assert.h> 12 #define pi acos(-1.) 13 using namespace std; 14 typedef long long ll; 15 const int int_inf = 0x3f3f3f3f; 16 const ll ll_inf = 1ll << 62; 17 const int INT_INF = (int)((1ll << 31) - 1); 18 const int mod = 1e6 + 7; 19 const double double_inf = 1e30; 20 typedef unsigned long long ul; 21 #pragma comment(linker, "/STACK:102400000,102400000") 22 #define max(a, b) ((a) > (b) ? (a) : (b)) 23 #define min(a, b) ((a) < (b) ? (a) : (b)) 24 #define mp make_pair 25 #define st first 26 #define nd second 27 #define keyn (root->ch[1]->ch[0]) 28 #define lson (u << 1) 29 #define rson (u << 1 | 1) 30 #define pii pair<int, int> 31 #define pll pair<ll, ll> 32 #define pb push_back 33 #define type(x) __typeof(x.begin()) 34 #define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++) 35 #define FOR(i, s, t) for(int i = (s); i <= (t); i++) 36 #define ROF(i, t, s) for(int i = (t); i >= (s); i--) 37 #define dbg(x) cout << x << endl 38 #define dbg2(x, y) cout << x << " " << y << endl 39 #define clr(x, i) memset(x, (i), sizeof(x)) 40 #define maximize(x, y) x = max((x), (y)) 41 #define minimize(x, y) x = min((x), (y)) 42 #define low_bit(x) ((x) & (-x)) 43 44 inline int readint(){ 45 int x; 46 scanf("%d", &x); 47 return x; 48 } 49 50 inline int readstr(char *s){ 51 scanf("%s", s); 52 return strlen(s); 53 } 54 55 class cmpt{ 56 public: 57 bool operator () (const int &x, const int &y) const{ 58 return x > y; 59 } 60 }; 61 62 int Rand(int x, int o){ 63 //if o set, return [1, x], else return [0, x - 1] 64 if(!x) return 0; 65 int tem = (int)((double)rand() / RAND_MAX * x) % x; 66 return o ? tem + 1 : tem; 67 } 68 69 void data_gen(){ 70 srand(time(0)); 71 freopen("in.txt", "w", stdout); 72 int times = 10; 73 printf("%d ", times); 74 while(times--){ 75 int n = Rand(500, 1), m = Rand(500, 1); 76 printf("%d %d ", n, m); 77 FOR(i, 1, n){ 78 FOR(j, 1, m) printf("%c", Rand(2, 0) + 'a'); 79 putchar(' '); 80 } 81 n = Rand(min(10, n), 1), m = Rand(min(10, m), 1); 82 printf("%d %d ", n, m); 83 FOR(i, 1, n){ 84 FOR(j, 1, m) printf("%c", Rand(2, 0) + 'a'); 85 putchar(' '); 86 } 87 } 88 } 89 90 struct cmpx{ 91 bool operator () (int x, int y) { return x > y; } 92 }; 93 int debug = 0; 94 int dx[] = {-1, 1, 0, 0}; 95 int dy[] = {0, 0, -1, 1}; 96 //------------------------------------------------------------------------- 97 const int maxn = 12; 98 const int sigma_size = 26; 99 ll dp[30][1 << 12][maxn * maxn]; 100 int nex[maxn * maxn][sigma_size]; 101 int state[maxn * maxn]; 102 int info[maxn * maxn]; 103 int tot; 104 map<string, int> mapi; 105 struct Trie{ 106 int ch[maxn * maxn][sigma_size]; 107 int idx(char c) { return c - 'a'; } 108 int sz; 109 void init() { clr(ch[0], 0); sz = 0; clr(info, 0); } 110 void insert(char *s){ 111 int u = 0; 112 while(*s){ 113 int v = ch[u][idx(*s)]; 114 if(!v) { ch[u][idx(*s)] = v = ++sz; clr(ch[sz], 0); } 115 u = v; 116 ++s; 117 } 118 if(!info[u]) info[u] = ++tot; 119 } 120 121 char tem[20]; 122 int k; 123 124 void dfs1(int u){ 125 FOR(i, 0, sigma_size - 1){ 126 int v = ch[u][i]; 127 if(!v) continue; 128 tem[k++] = i + 'a', tem[k] = '