题意

题目给出m(m<=10)个单词,每个单词的长度不超过10且仅由小写字母组成,给出一个正整数n(n<=25)和正整数k,问有多少方法可以组成长度为n的文本且最少包含k个给出的单词。

分析

和上一个AC自动机很相似,上一篇博客是不包含任何一个单词长度为n的方案数,这个题是包含至少k个单词的方案数,而且n,m,k都非常的小。

按照前面的经验很容易想到,我们还是得先建一个AC自动机,然后把它的单词结点标记出来。与前面不同的是我们在状态转移的时候需要考虑到当前走过的结点已经包含多少单词了。所以我们想到用dp[i][j][k]来表示当前在i结点,已经走了j步,且走过了k个单词结点。但是我们发现,这样表示状态的话没有办法转移,因为当我们遇到一个单词结点的时候,我们并不知道这个单词节点前面时候已经走过被计数了。所以我们想到,要使用状态压缩dp来解决这个题目。

f[i][j][S]当前在i结点,还需要走j步,包含的结点由S通过二进制来表示。在建AC自动机的时候,用match[i]=1<<j,来表示i结点是单词j的单词结点。

f[i][j][S]=sum(f[v][j-1][S|match[v]]).其中v是结点i的儿子结点。

当j==0时,如果S中包含的单词数目>=k,则f[i][0][S]=1,否则为0

然后我们就很容易用记忆搜索解决这个问题。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue> using namespace std;
const int maxnode=;
const int MOD=;
const int sigma_size=;
int ch[maxnode][sigma_size],match[maxnode],f[maxnode];
int dp[maxnode][][(<<)+],vis[maxnode][][(<<)+];
int sz;
void init(){
sz=;
memset(ch[],,sizeof(ch[]));
memset(vis,,sizeof(vis));
match[]=;
}
void insert(char *s,int v){
int n=strlen(s),u=;
for(int i=;i<n;i++){
int c=s[i]-'a';
if(!ch[u][c]){
ch[u][c]=sz;
memset(ch[sz],,sizeof(ch[sz]));
match[sz++]=;
}
u=ch[u][c];
}
match[u]|=(<<v);
} void getFail(){
queue<int>q;
f[]=;
for(int i=;i<sigma_size;i++){
int u=ch[][i];
if(u){
q.push(u);
f[u]=;
}
}
while(!q.empty()){
int r=q.front();q.pop();
for(int i=;i<sigma_size;i++){
int u=ch[r][i];
if(!u){
ch[r][i]=ch[f[r]][i];
continue;
}
q.push(u);
int v=f[r];
while(v&&!ch[v][i])v=f[v];
f[u]=ch[v][i];
match[u]|=match[f[u]];
}
}
}
int n,m,k;
char s[];
int Count(int S){
int res=;
for(int i=;i<m;i++){
if(S&(<<i))
res++;
}
return res;
}
int DP(int u,int L,int S){
if(vis[u][L][S])
return dp[u][L][S];
vis[u][L][S]=;
int &ans=dp[u][L][S];
ans=;
if(L==){
if(Count(S)>=k){
return ans=;
}
return ans=;
}
for(int i=;i<sigma_size;i++){
int v=ch[u][i];
ans=(ans%MOD+DP(v,L-,S|match[v])%MOD)%MOD;
}
return ans;
}
int main(){
while(scanf("%d%d%d",&n,&m,&k)!=EOF&&(n||m||k)){
init();
for(int i=;i<m;i++){
scanf("%s",s);
insert(s,i);
}
getFail();
int ans=DP(,n,);
printf("%d\n",ans%MOD);
}
return ;
}

【HDU2825】Wireless Password【AC自动机,状态压缩DP】的更多相关文章

  1. HDU2825 Wireless Password —— AC自动机 + 状压DP

    题目链接:https://vjudge.net/problem/HDU-2825 Wireless Password Time Limit: 2000/1000 MS (Java/Others)    ...

  2. hdu2825 Wireless Password(AC自动机+状压dp)

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

  3. HDU-2825 Wireless Password(AC自动机+状压DP)

    题目大意:给一系列字符串,用小写字母构造出长度为n的至少包含k个字符串的字符串,求能构造出的个数. 题目分析:在AC自动机上走n步,至少经过k个单词节点,求有多少种走法. 代码如下: # includ ...

  4. HDU 4511 (AC自动机+状态压缩DP)

    题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...

  5. POJ 3691 (AC自动机+状态压缩DP)

    题目链接:  http://poj.org/problem?id=3691 题目大意:给定N个致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题 ...

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

    题意:容易理解... 分析:题目中给的模式串的个数最多为10个,于是想到用状态压缩dp来做,它的状态范围为1-2^9,所以最大为2^10-1,那我们可以用:dp[i][j][k]表示长度为i,在tri ...

  7. bzoj1195 神奇的ac自动机+状态压缩dp

    /* 难的不是ac自动机,是状态压缩dp 之前做了一两题类似题目,感觉理解的还不够透彻 */ #include<iostream> #include<cstdio> #incl ...

  8. 【HDU2825】Wireless Password (AC自动机+状压DP)

    Wireless Password Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u De ...

  9. HDU 4057 Rescue the Rabbit ( AC自动机 + 状态压缩DP )

    模板来自notonlysuccess. 模式串只有10个,并且重复出现的分值不累加,因此很容易想到状态压缩. 将模式串加入AC自动机,最多有10*100个状态. dp[i][j][k]:串长为i,在T ...

  10. 计蒜客-蒜场抽奖(AC自动机+状态压缩DP)

    题解:题意不再说了,题目很清楚的. 思路:因为N<=10,所以考虑状态压缩 AC自动机中 val[1<<i]: 表示第i个字符串.AC自动机中fail指针是指当前后缀在其他串里面所能 ...

随机推荐

  1. Docker-Compose API too old for Windows

    I was working on some code with a Docker Windows container today and ran into this error message: ER ...

  2. Makefile编写 五 隐含规则

    隐含规则———— 在我们使用Makefile时,有一些我们会经常使用,而且使用频率非常高的东西,比如,我们编译C/C++的源程序为中间目标文件(Unix下是[.o]文件,Windows下是[.obj] ...

  3. JVM内存管理之GC算法精解(复制算法与标记/整理算法)

    本次LZ和各位分享GC最后两种算法,复制算法以及标记/整理算法.上一章在讲解标记/清除算法时已经提到过,这两种算法都是在此基础上演化而来的,究竟这两种算法优化了之前标记/清除算法的哪些问题呢? 复制算 ...

  4. linux中日志文件查找,根据关键字,vi命令,awk和wc

    参考: http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2856896.html 当时需求:查看系统日志,统计系统的处理时间(从请求进去系统到系 ...

  5. crontab 定时任务设置

    CRONTAB概念/介绍 crontab命令用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行. cron 系统调度进程. 可以使用它在 ...

  6. 第十三章 hadoop机架感知

    背景 分布式的集群通常包含非常多的机器,由于受到机架槽位和交换机网口的限制,通常大型的分布式集群都会跨好几个机架,由多个机架上的机器共同组成一个分布式集群.机架内的机器之间的网络速度通常都会高于跨机架 ...

  7. Linux文件属性,类型,ls -lhi解释行列

    Linux文件属性(描述信息) -i inode节点号 -h 人类可读 ls -lhi 1703938 drwxr-xr-x 2 rsync rsync 4.0K Jun 7 07:24 gamese ...

  8. 关于模拟admin实现stark组件的知识点

    一. url知识 还记得include分发么?里面的参数都可以有些什么? urlconf_module本质是返回的是模块路径对象 def include(arg, namespace=None, ap ...

  9. OpenCV for Python常用命令

      读取图像首先要导入OpenCV包 import cv2 OpenCV目前支持读取bmp.jpg.png.tiff等常用格式. //读取图片 img2 = cv2.imread('out-0022. ...

  10. 【做题记录】USACO gold * 50(第一篇)

    orz xhk 5/50 1597: [Usaco2008 Mar]土地购买 $ f[i]=min(f[j]+x[i]*y[j+1]) $ 然后斜率优化 1699: [Usaco2007 Jan]Ba ...