hdu2825

题意

给出一些字符串,要求构造一个长度为 \(n\) 的字符串至少包括其中的 \(k\) 个,问有多少种字符串满足条件。

分析

AC自动机 构造状态转移,然后 状态压缩DP 即可。

\(dp[i][j][k]\) 表示长度为 \(i\) 在 AC自动机上的状态为 \(j\) 已包含的字符串为 \(k\) 时的字符串数量( \(k\) 二进制表示是否有某个给出的字符串)。

code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int MAXN = 1e2 + 10;
const int MOD = 20090717;
struct Trie {
int root, L, nxt[MAXN][26], fail[MAXN], val[MAXN];
int newnode() {
memset(nxt[L], -1, sizeof nxt[L]);
return L++;
}
void init() {
L = 0;
root = newnode();
memset(val, 0, sizeof val);
memset(fail, 0, sizeof fail);
}
void insert(int id, char S[]) {
int len = strlen(S);
int now = root;
for(int i = 0; i < len; i++) {
int d = S[i] - 'a';
if(nxt[now][d] == -1) nxt[now][d] = newnode();
now = nxt[now][d];
}
val[now] |= (1 << id);
}
void build() {
queue<int> Q;
for(int i = 0; i < 26; i++) {
if(nxt[root][i] == -1) nxt[root][i] = 0;
else { fail[nxt[root][i]] = root; Q.push(nxt[root][i]); }
}
while(!Q.empty()) {
int now = Q.front(); Q.pop();
val[now] |= val[fail[now]];
for(int i = 0; i < 26; i++) {
if(nxt[now][i] == -1) nxt[now][i] = nxt[fail[now]][i];
else { fail[nxt[now][i]] = nxt[fail[now]][i]; Q.push(nxt[now][i]); }
}
}
}
}trie;
int dp[30][MAXN][1024];
int cnt[1024];
int main() {
int n, m, k;
cnt[0] = 0;
for(int i = 1; i < 1024; i++) {
int j = 0;
while(!((i >> j) & 1)) j++;
cnt[i] = cnt[i - (1 << j)] + 1;
}
while(~scanf("%d%d%d", &n, &m, &k) && (n + m + k)) {
trie.init();
for(int i = 0; i < m; i++) {
char s[15];
scanf("%s", s);
trie.insert(i, s);
}
trie.build();
for(int i = 0; i <= n; i++) {
for(int j = 0; j < trie.L; j++) {
for(int k = 0; k < (1 << m); k++) {
dp[i][j][k] = 0;
}
}
}
dp[0][0][0] = 1;
for(int i = 0; i < n; i++) {
for(int j = 0; j < trie.L; j++) {
for(int bit = 0; bit < (1 << m); bit++) {
if(!dp[i][j][bit]) continue;
for(int k = 0; k < 26; k++) {
int tmp = trie.nxt[j][k];
(dp[i + 1][tmp][trie.val[tmp] | bit] += dp[i][j][bit]) %= MOD;
}
}
}
}
int sum = 0;
for(int i = 0; i < trie.L; i++) {
for(int j = 0; j < (1 << m); j++) {
if(cnt[j] >= k) sum = (sum + dp[n][i][j]) % MOD;
}
}
printf("%d\n", sum);
}
return 0;
}

最新文章

  1. JavaScript闭包之“词法作用域”
  2. [后端人员耍前端系列]AngularJs篇:30分钟快速掌握AngularJs
  3. muduo库安装
  4. PHP、C++的重载
  5. python 数据结构之双向链表的实现
  6. 被Play framework狠狠的play了一把
  7. HDU 4893 Wow! Such Sequence! (线段树)
  8. 跟Microsoft.AspNet.Identity学习哈希加盐法
  9. 欲练JS,必先攻CSS——前端修行之路(码易直播)
  10. error MSB8008: 指定的平台工具集(v110)未安装或无效。请确保选择受支持的 PlatformToolset 值
  11. js和jquery实现监听键盘事件
  12. MATLAB程序:用FCM分割脑图像
  13. Flink 核心技术浅析(整理版)
  14. A*搜索详解(2)——再战觐天宝匣
  15. python变量和变量赋值的几种形式
  16. /linux-command-line-bash-shortcut-keys/
  17. linux之tree命令
  18. dropwizard使用cors支持跨域浏览器取不到自定义header问题
  19. C#中public与private与static
  20. 浅谈Comparable与Comparator的区别

热门文章

  1. c# 以多个字符串分隔字符串数据 分组 分隔 split 正则分组
  2. [Leetcode] String to integer atoi 字符串转换成整数
  3. BZOJ day1
  4. 如何获取iframe DOM的值
  5. 论文笔记《Spatial Memory for Context Reasoning in Object Detection》
  6. JSOI2008 星球大战 [并查集]
  7. Codeforces Round #520 (Div. 2) A. A Prank
  8. wait , notify 模拟 Queue
  9. 入门级:GitHub和Git超超超详细使用教程!
  10. sublime JSX Html 标签补全