给定属于字符集 A..Z A .. Z 的若干字符串,求随机生成的所有长度为 m m 的字符串中,给定的某些字符串是生成字符串的子串的数量。

哎呀团长本来是想把辣鸡题面翻译的简洁易懂的但是感觉越翻译越不可读。。讲真我语文老师人很棒而且活的好好的只是我不听话。。

这个题乍一看和「BZOJ1009」蛮像的,只是把一个串改成了多个串,那么相应的我们就把KMP换成AC自动机就好了嘛。

而且和上述题目不同的是,这个题并不需要用矩阵乘法23333333333333333333333.

好像代码说的比我 xjb bb 来的好得多。。

代码

#include <cstdio>
#include <cstring>
#include <climits>
#include <queue>
#include <vector>
#include <algorithm>
const char BASE = 'A';
const int SIZE = 26;
const int MAX_N = 60;
const int MAX_M = 100;
const int MOD = 10007;
struct AC_Automaton {
struct Node {
int id;
Node *c[SIZE], *fail, *next;
bool isWord;
Node(bool isWord = false) : c(), fail(NULL), next(NULL), isWord(isWord) {}
} *root;
void insert(const char *begin, const char *end) {
Node **v = &root;
for (const char *p = begin; p != end; p++) {
if (!*v) *v = new Node(false);
v = &(*v)->c[*p];
}
if (!*v) *v = new Node(true);
else (*v)->isWord = true;
}
void build() {
std::queue<Node *> q;
root->fail = root, root->next = NULL;
q.push(root);
while (!q.empty()) {
Node *v = q.front();
q.pop();
v->isWord |= v->fail->isWord;
for (int i = 0; i < SIZE; i++) {
Node *&c = v->c[i];
if (!c) {
c = v == root ? root : v->fail->c[i];
continue;
}
Node *u = v->fail;
c->fail = v != root && u->c[i] ? u->c[i] : root;
// c->next = c->fail->isWord ? c->fail : c->fail->next;
q.push(c);
}
}
}
void getNodeList(std::vector<Node *> &vec) {
std::queue<Node *> q;
q.push(root);
while (!q.empty()) {
Node *v = q.front();
q.pop();
vec.push_back(v);
for (int i = 0; i < SIZE; i++) if (v->c[i]) q.push(v->c[i]);
}
}
} ac;
inline int pow(int a, int n) {
int res = 1;
for (; n; n >>= 1, a = (long long)a * a % MOD) if (n & 1) res = (long long)res * a % MOD;
return res;
}
int f[MAX_M + 1][MAX_N * MAX_M + 100];
char s[MAX_M];
std::vector<AC_Automaton::Node *> nodes;
int main() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%s", s);
int len = strlen(s);
for (int j = 0; j < len; j++) s[j] -= BASE;
ac.insert(s, s + len);
}
ac.getNodeList(nodes);
#ifdef DBG
printf("size of the node list : %d\n", nodes.size());
#endif
ac.build();
for (int i = 0; i < nodes.size(); i++) nodes[i]->id = i;
memset(f, 0, sizeof(f));
f[0][0] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 0; j < nodes.size(); j++) {
if (!nodes[j]->isWord && f[i - 1][j] > 0) {
for (int k = 0; k < SIZE; k++) {
f[i][nodes[j]->c[k]->id] = (f[i][nodes[j]->c[k]->id] + f[i - 1][j]) % MOD;
}
}
}
}
int ans = 0;
for (int i = 0; i < nodes.size(); i++) {
if (!nodes[i]->isWord) (ans += f[m][i]) %= MOD;
}
printf("%d", ((pow(26, m) - ans) % MOD + MOD) % MOD);
}