题意:一个密码,长度为 n,然后有m个magic words,这个密码至少由k个magic words组成。

问这个密码可能出现的总数。

思路:首先构造AC自动机,由于m很小,才10 ,我们可以使用二进制来表示每个magic words的使用情况。

对于dp[i][j][k],表示长度为i 时,匹配到j这个节点,当前选取的magic words是k 状态时的最大数量。

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
using namespace std;
#define MOD 20090717
#define N 1111111
int n , m , k ;
int cnt ;
struct AC_AUTO {
int next[26] ;
int fail ;
int st ;
void init() {
mem(next ,0) ;
fail = -1 ;
st = 0 ;
}
} a[500000];
int vis[111111] ;
void show(int now) {
vis[now] = 1 ;
cout << now << " " << a[now].fail << endl;
for (int i = 0 ; i < 26 ; i ++ ) {
if(a[now].next[i] != 0 && !vis[a[now].next[i]]) {
show(a[now].next[i]) ;
}
}
}
void insert(char *s,int k) {
int p = 0 ;
for(int i = 0 ; s[i] ; i ++) {
int t = s[i] - 'a' ;
if(a[p].next[t] == 0) {
a[cnt].init() ;
a[p].next[t] = cnt ++ ;
}
p = a[p].next[t] ;
}
a[p].st |= (1 << k) ;
}
int q[111111] ;
void ac_bfs() {
int i,head = 0,tail = 0;
q[tail ++]=0;
while(head < tail) {
int front = q[head ++];
for(i = 0; i < 26 ; i ++) {
if(a[front].next[i] == 0) {///
if(front == 0)a[front].next[i] = 0 ;
else a[front].next[i] = a[a[front].fail].next[i] ;
} else {
int p = a[front].fail ;
while(p != -1) {
if(a[p].next[i] != 0) {
a[a[front].next[i]].fail = a[p].next[i] ;
a[a[front].next[i]].st |= a[a[p].next[i]].st ;
break ;
}
p = a[p].fail ;
}
if(p == -1)a[a[front].next[i]].fail = 0 ;
q[tail ++] = a[front].next[i] ;
}
}
}
}
int dp[26][200][1 << 10] ; int solve() {
for (int i = 0 ; i <= n ; i ++ )
for (int j = 0 ; j <= cnt ; j ++ )
for (int x = 0 ; x <= 1 << m ; x ++ )
dp[i][j][x] = 0 ;
dp[0][0][0] = 1 ;
for (int i = 0 ; i < n ; i ++ )//长度为i时
for (int j = 0 ; j < cnt ; j ++ )//在第j个节点
for (int x = 0 ; x < 1 << m ; x ++) { //第x个状态
if(!dp[i][j][x])continue ;
for (int y = 0 ; y < 26 ; y ++ ) { //字母y
int newj = a[j].next[y] ;
int newst = x | a[newj].st ;
dp[i + 1][newj][newst] = (dp[i][j][x] + dp[i + 1][newj][newst] ) % MOD ;
}
}
int ans = 0 ;
for (int i = 0 ; i < 1 << m ; i ++ ) {
int ret = 0 ;
int d = i ;
for (; d ; d -= d & (-d) , ret ++) ;
if(ret < k )continue ;
for (int j = 0 ; j < cnt ; j ++ ) {
ans = (ans + dp[n][j][i]) % MOD ;
}
}
return ans ;
}
char in[111] ;
int main() {
while(cin >> n >> m >> k, (n + m + k)) {
a[0].init() ;
cnt = 1 ;
for (int i = 0 ; i < m ; i ++ ) {
scanf("%s",in) ;
insert(in , i) ;
}
ac_bfs() ;
printf("%d\n",solve()) ;
}
return 0 ;
}

HDU 2825 AC自动机+DP的更多相关文章

  1. hdu 2825 aC自动机+状压dp

    Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  2. hdu 2296 aC自动机+dp(得到价值最大的字符串)

    Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  3. hdu 2457(ac自动机+dp)

    题意:容易理解... 分析:这是一道比较简单的ac自动机+dp的题了,直接上代码. 代码实现: #include<stdio.h> #include<string.h> #in ...

  4. Lost's revenge HDU - 3341 AC自动机+DP(需要学会如何优雅的压缩状态)

    题意: 给你n个子串和一个母串,让你重排母串最多能得到多少个子串出现在重排后的母串中. 首先第一步肯定是获取母串中每个字母出现的次数,只有A T C G四种. 这个很容易想到一个dp状态dp[i][A ...

  5. DNA repair HDU - 2457 AC自动机+DP

    题意: 给你N个模板串,并且给你一个文本串, 现在问你这个文本串最少需要改变几个字符才能使得它不包含任何模板串. (以上字符只由A,T,G,C构成) 题解: 刚开始做这一题的时候表示很懵逼,好像没有学 ...

  6. hdu 2825(ac自动机+状态压缩dp)

    题意:容易理解... 分析:在做这道题之前我做了hdu 4057,都是同一种类型的题,因为题中给的模式串的个数最多只能为10个,所以我们就很容易想到用状态压缩来做,但是开始的时候我的代码超时了dp时我 ...

  7. HDU 2425 DNA repair (AC自动机+DP)

    DNA repair Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  8. HDU 3341 Lost's revenge AC自动机+dp

    Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)T ...

  9. HDU 2457 DNA repair(AC自动机+DP)题解

    题意:给你几个模式串,问你主串最少改几个字符能够使主串不包含模式串 思路:从昨天中午开始研究,研究到现在终于看懂了.既然是多模匹配,我们是要用到AC自动机的.我们把主串放到AC自动机上跑,并保证不出现 ...

随机推荐

  1. 将 Shiro 作为一个许可为基础的应用程序 五:password加密/解密Spring应用

    考虑系统password的安全,眼下大多数系统都不会把password以明文的形式存放到数据库中. 一把会採取下面几种方式对password进行处理 password的存储 "编码" ...

  2. C++学习之路—继承与派生(四)拓展与总结

    (根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 1    拓展部分 本节主要由两部分内容组成,分 ...

  3. 8天玩转并行开发——第八天 用VS性能向导解剖你的程序

    原文 8天玩转并行开发——第八天 用VS性能向导解剖你的程序 最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需 ...

  4. 【Demo 0001】Android 程序结构

    Android 学习步骤及内容:     1.  Android 程序结构(开发环境搭建,Android第一程序,程序启动过程以及工程介绍):     2.  Android 事件(通用使用规则,通用 ...

  5. display:table 水平居中

    <div style="width:auto; margin:auto;display:table"> <div style="width: 100px ...

  6. 斐讯K2 V22.X.X.X 新版固件 刷机教程 (开telnet,安装SSH,adbyby,刷breed,华硕Padavan)

    源:http://www.right.com.cn/forum/thread-191833-1-1.html 属于我的上一个帖子的升级版,基本属于无脑操作,点击恢复就可以自动刷好breed,浏览上传新 ...

  7. 14.6.3 Grouping DML Operations with Transactions 组DML操作

    14.6.3 Grouping DML Operations with Transactions 组DML操作 默认情况下,连接到MySQL server 开始是以启动自动提交模式, 会自动提交每条S ...

  8. expect 参数处理之一

    expect 参数处理之一 expect是很强悍的脚本,网上资源虽然很经典,但很少,我把自己的测试脚本贴之,仅作参考 #!/usr/bin/expect -f proc help {} { puts ...

  9. COCOS2D-X之帧动画的一种实现Demo

    这个Demo主要是实现帧动画,建议游戏中少用帧动画.废话少说直接上代码. 一.我们直接在COCOS2D-X自带的HelloCpp的工程中添加代码即可.我们在初始化中添加如下代码并附上图片资源. CCS ...

  10. [读书笔记]黑客与画家[Hackers.and.Painters]

    (书生注:这本书写的不错.针对程序员,可以带来不同角度的想法,有助于反思自己的程序员工作.我甚至从中发现了自己爱用铅笔的原因...  尤其是其中关于黑客的定义,包括黑客认为的乐趣和目的,让人更深层次思 ...