HDU 2825 Wireless Password ( Trie图 && 状态压缩DP )
题意 : 输入n、m、k意思就是给你 m 个模式串,问你构建长度为 n 至少包含 k 个模式串的方案有多少种
分析 : ( 以下题解大多都是在和 POJ 2778 && POJ 1625 && HDU 2243 进行类比,如果没做过的话.......可能看不懂 )
这道题如果去对比之前做过的 POJ 2778 And HDU 2243 可以发现现在的难点在于如何找出至少包含 k 个模式串的,这里我们给每一个单词编号,对于在DP过程当中选中了这个单词就标记一下,但是问题是如何判断是否被重复选过以及如何标记?如果直接开在DP的维度上那是不可能的!(即开一个十维数组来记录每一个单词是否被选过),如果能将这十个维度压缩成一个维度多好啊!没错了,使用二进制,二进制的每一位代表每一个单词,0就是没被选,1就是被选,最多只需要十位便能记录这些信息,转化为十进制之后我们只要给DP再多添一个维度即可。那么代码怎么实现呢?只需要用到 | 操作符即可,这个操作符会把每一位的 1 进行叠加,相当于吧信息进行叠加!不过这里需要注意,在做POJ 1625 的时候是用一个矩阵来转移的,而这道题不能,因为我们还附加了一个选了哪几个单词这一个维度,如果全部笼统的映射到矩阵上的话是不行的!比如 G[i][j] 代表从 i 到 j 一步走完的可行方案,但是我们不知道这些方案到底走过了那些单词,所以需要一步步转移,如果把 POJ 1625 的代码不用矩阵来储存信息那要怎么写呢?如下( 如果你之前看过我 POJ 1625 的代码的话 )
; i<m; i++)
; j<ac.Size; j++){
// for(int k=0; k<ac.Size; k++){
// dp[i+1][k] += dp[i][j] * G[j][k];
// }
; k<n; k++){
int tmp = ac.Node[j].Next[k];
if(!ac.Node[tmp].flag)
dp[i+][tmp] += dp[i][j];
}
}
所以在网上搜这道题的题解的时候,一开始我有点懵,为什么有四层for?这和用矩阵有什么区别?实际上矩阵写法完全可以写成如上所示!
因此总结一下就是 利用DP[i][j][k] 表示 DP[第几步][哪个节点结尾][当前选了哪些单词] = 方案数
这里有个大优化,因为我们的DP是一个向前的DP,这样的DP有一个优势,就是当 DP值 == 0 的时候将不会对后面有任何影响,直接continue便能减去大量的“枝”!
#include<string.h>
#include<stdio.h>
#include<queue>
using namespace std;
;
;
;
][][(<<)+];
];
struct Aho{
struct StateTable{
int Next[Letter];
int fail, id;
}Node[Max_Tot];
int Size;
queue<int> que;
inline void init(){
while(!que.empty()) que.pop();
memset(Node[].Next, , ].Next));
Node[].fail = Node[].id = ;
Size = ;
}
inline void insert(char *s, int id){
;
; s[i]; i++){
int idx = s[i] - 'a';
if(!Node[now].Next[idx]){
memset(Node[Size].Next, , sizeof(Node[Size].Next));
Node[Size].fail = Node[Size].id = ;
Node[now].Next[idx] = Size++;
}
now = Node[now].Next[idx];
}
Node[now].id |= (<<id);
}
inline void BuildFail(){
Node[].fail = ;
; i<Letter; i++){
].Next[i]){
Node[Node[].Next[i]].fail = ;
que.push(Node[].Next[i]);
}].Next[i] = ;
}
while(!que.empty()){
int top = que.front(); que.pop();
Node[top].id |= Node[Node[top].fail].id;
; i<Letter; i++){
int &v = Node[top].Next[i];
if(v){
que.push(v);
Node[v].fail = Node[Node[top].fail].Next[i];
}else v = Node[Node[top].fail].Next[i];
}
}
}
}ac;
];
int main(void)
{
; i<(<<); i++){
cnt[i] = ;
; j<; j++){
<<j))
cnt[i]++;
}
}
int n, m, k;
while(~scanf("%d %d %d", &n, &m, &k)){
&& m== && k==) break;
ac.init();
; i<m; i++){
scanf("%s", S);
ac.insert(S, i);
}
ac.BuildFail();
; i<=n; i++)
; j<ac.Size; j++)
; l<(<<m); l++)
dp[i][j][l] = ;
dp[][][] = ;
; i<n; i++){
; j<ac.Size; j++){
; l<(<<m); l++){
){
; x<Letter; x++){///不用矩阵了,一步步转移
;
int newj = ac.Node[j].Next[x];
int newl = (ac.Node[ newj ].id) | l;///加入了哪个新节点就应该去叠加状态!
dp[newi][newj][newl] += dp[i][j][l];
dp[newi][newj][newl] %= MOD;
}
}
}
}
}
;
; i<(<<m); i++){
if(cnt[i]>=k){
; j<ac.Size; j++){
ans = (ans + dp[n][j][i])%MOD;
}
}
}
printf("%d\n", ans%MOD);
}
;
}
HDU 2825 Wireless Password ( Trie图 && 状态压缩DP )的更多相关文章
- HDU - 2825 Wireless Password(AC自己主动机+DP)
Description Liyuan lives in a old apartment. One day, he suddenly found that there was a wireless ne ...
- hdu 4057 AC自己主动机+状态压缩dp
http://acm.hdu.edu.cn/showproblem.php?pid=4057 Problem Description Dr. X is a biologist, who likes r ...
- HDU 2825 Wireless Password (AC自己主动机,DP)
pid=2825">http://acm.hdu.edu.cn/showproblem.php? pid=2825 Wireless Password Time Limit: 2000 ...
- hdu 2825 Wireless Password(ac自己主动机&dp)
Wireless Password Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- [AC自己主动机+状压dp] hdu 2825 Wireless Password
题意: 给n.m,k ,再给出m个单词 问长度为n的字符串.至少在m个单词中含有k个的组成方案有多少种. 思路: 因为m最大是10,所以能够採取状压的思想 首先建立trie图,在每一个单词的结束节点标 ...
- HDU 5418 Victor and World (状态压缩dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5418 题目大意:有n个结点m条边(有边权)组成的一张连通图(n <16, m<100000 ...
- hdu 5067 Harry And Dig Machine (状态压缩dp)
题目链接 bc上的一道题,刚开始想用这个方法做的,因为刚刚做了一个类似的题,但是想到这只是bc的第二题, 以为用bfs水一下就过去了,结果MLE了,因为bfs的队列里的状态太多了,耗内存太厉害. 题意 ...
- HDU 4649 Professor Tian(反状态压缩dp,概率)
本文出自 http://blog.csdn.net/shuangde800 题目链接:点击打开链接 题目大意 初始有一个数字A0, 然后给出A1,A2..An共n个数字,这n个数字每个数字分别有一 ...
- HDU - 2825 Wireless Password (AC自动机+状压DP)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2825 题意:给一些字符串,构造出长度为n的字符串,它至少包含k个所给字符串,求能构造出的个数. 题解: ...
随机推荐
- appium常见问题01_android筛选下拉框无法定位问题
近期用appium做android自动化的过程中,遇到一种筛选下拉框,神奇的是,定位工具定位怎样都定位不到. 首先尝试用uiaotomator工具定位,无法定位到下拉框元素,只能定位到底层元素: 询问 ...
- python中的各个模块
collection模块:python中的扩展数据模块#namedtuple: 生成可以使用名字来访问元素内容的tuple'''from collections import namedtuplePo ...
- Android - Unable to add window android.view.ViewRootImpl$W@6518342 -- permission denied for window type 2133
因为跟博主碰到了一样的问题,所以记录一下分析原理 原文链接:https://www.jianshu.com/p/b0364074288a 首先,先介绍下背景环境,第一,是Android7.0,其次,要 ...
- ascx
aspx是页面文件ascx是用户控件,用户控件必须嵌入到aspx中才能使用. ascx是用户控件,相当于模板 其实ascx你可以理解为Html里的一部分代码,只是嵌到aspx里而已,因为aspx内容多 ...
- nodejs 对接微信 express 对接微信
安装引用 npm install express npm install body-parser npm install express-xml-bodyparser npm install axio ...
- mysqlreport 安装&使用
安装包:mysqlreport-3.5.tgz 下载地址:http://hackmysql.com/scripts/mysqlreport-3.5.tgz 安装办法:[root@nagios ~]# ...
- Linux常用命令基础
linux 常用指令 基础命令 宿主目录 目录结构 文件管理 目录管理 用户管理 别名管理 压缩包管理 网络设置 shell技巧 帮助方法 /表示根目录 ~表示家目录 软件的安装(光盘中的软件呢): ...
- P1067多项式输出
这道题是2009普及组的题,仍然是一个字符串+模拟.(蒻到先不刷算法) 这道题的题干给了很多的提示,也很全面,但是当我把种种情况都考虑到了后,在写代码的过程中仍然出现了很多的错误,wa了三四次.其实导 ...
- antd组件Upload实现自己上传
前言 在实现图片上传时,可能需要用到Upload,但是它默认的上传方式是加入图片后直接上传,如果要实现最后再一次性上传,需要自定义内容. //添加按钮的样式 const uploadButton = ...
- 根据日志来源的不同生成不同的index索引
使用filebeat收集系统日志,不同应用的日志,然后把这些日志传输给Logstash,再然后交由elasticsearch处理,那么如何区分不同的日志来源呢? filebeat.yml配置文件中不启 ...