又忘了计数题算补集这回事了
感觉trie
的好处就是一个节点代表一个串啊?
又及: wdnmd真都一个错误犯三次啊
懵逼的 题目
BZOJ
扯淡的 题解
一开始想着是在trie
上遍历然后算贡献云云
然后发现这个容斥似乎有点反人类
然后抄题解第一句就是取补集
Emmmmm...
f[i][j]
代表当前生成第i
位,
匹配到了自动机的第j
个点上 没有出现过已知单词的方案数
然后随便写写就好了
沙茶的 代码
我构建fail
的时候又㕛叒叕忘了把下一层push
进去了
这是有多大仇...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
|
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <queue> #include <vector> #define MAXN (6000 + 5) #define MAXM (100 + 5) #define MAXC (26) #define Aufun (10007) using namespace std; struct node { int son[MAXC], fail; vector<int> bh; } b[MAXN]; int n, m, f[MAXM][MAXN], cntb, ans; char s[MAXM]; void init() { queue<int> q; for (int i = 0; i < MAXC; i++) if (b[0].son[i]) q.push(b[0].son[i]); while (!q.empty()) { int dq = q.front(); q.pop(); for (int i = 0; i < MAXC; i++) if (b[dq].son[i]) b[b[dq].son[i]].fail = b[b[dq].fail].son[i], q.push(b[dq].son[i]); else b[dq].son[i] = b[b[dq].fail].son[i]; } } int mpow(int a, int b) { int re = 1; for (int i = 1; i <= b; i++) re *= a, re %= Aufun; return re; } bool pd(int dq) { for (int i = dq; i; i = b[i].fail) if (b[i].bh.size()) return false; return true; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%s", s); int dqn = strlen(s), dq = 0; for (int j = 0; j < dqn; j++) { if (!b[dq].son[s[j] - 'A']) b[dq].son[s[j] - 'A'] = ++cntb; dq = b[dq].son[s[j] - 'A']; } b[dq].bh.push_back(i); } init(); f[0][0] = 1; for (int i = 0; i < m; i++) for (int j = 0; j <= cntb; j++) if (f[i][j]) for (int k = 0; k < MAXC; k++) if (pd(b[j].son[k])) f[i + 1][b[j].son[k]] += f[i][j], f[i + 1][b[j].son[k]] %= Aufun; for (int i = 0; i <= cntb; i++) ans += f[m][i], ans %= Aufun; printf("%d", ((mpow(26, m) - ans) % Aufun + Aufun) % Aufun); return 0; }
|
By 准备退役旅游的 Cansult