题意:有n个长度为len的模式串,问在所有长度为L的串中有多少个串符合如下条件:该串所有长度为len的子串都在这n个模式串中。
分析:动态规划,f[i][j]表示长度为i的以第j个模式串为后缀的符合条件的串有多少个,f[i + 1][k] += f[i][j];
k要符合第k个模式串可以由第j个模式串去掉首字母,再在结尾添加一个字母得到。就相当于我们不断的将模式串有重叠地(重叠长度为len-1)搭在当前构成的长度为i的串的结尾,使长度变为i+1。
也就是第k个模式串就是长度为i+1的串比长度为i的串多出的那个长度为len的子串(长度为i+1的串的长度为len的子串个数只比长度为i的串的长度为len的子串个数多1)。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; #define maxn 605 #define maxl 30 #define maxm 105 struct Edge { int next, v; }edge[maxn * maxn]; int head[maxn]; int comb_cnt, type_cnt, streamer_len; int comb_len; char comb[maxn][maxl]; int ecount; int f[maxm][maxn]; void input() { for (int i = 0; i < comb_cnt; i++) scanf("%s", comb[i]); } void addedge(int a, int b) { edge[ecount].v = b; edge[ecount].next = head[a]; head[a] = ecount++; } bool connect1(char *a, char *b) { for (int i = 1; i < comb_len; i++) if (a[i] != b[i - 1]) return false; return true; } void make() { comb_len = strlen(comb[0]); ecount = 0; memset(head, -1, sizeof(head)); for (int i = 0; i < comb_cnt; i++) for (int j = 0; j < comb_cnt; j++) if (connect1(comb[i], comb[j])) addedge(i, j); } void work() { memset(f, 0, sizeof(f)); for (int i = 0; i < comb_cnt; i++) f[comb_len][i] = 1; for (int i = comb_len; i < streamer_len; i++) for (int j = 0; j < comb_cnt; j++) for (int k = head[j]; k != -1; k = edge[k].next) f[i + 1][edge[k].v] += f[i][j]; int ans = 0; for (int i = 0; i < comb_cnt; i++) ans += f[streamer_len][i]; printf("%d\n", ans); } int main() { while (scanf("%d%d%d", &type_cnt, &streamer_len, &comb_cnt), type_cnt | streamer_len | comb_cnt) { input(); make(); work(); } return 0; }