\(\quad\)Great! Your new software is almost finished! The only thing left to do is archiving all your n resource files into a big one.
\(\quad\)Wait a minute… you realized that it isn’t as easy as you thought. Think about the virus killers. They’ll find your software suspicious, if your software contains one of the m predefined virus codes. You absolutely don’t want this to happen.
\(\quad\)Technically, resource files and virus codes are merely 01 strings. You’ve already convinced yourself that none of the resource strings contain a virus code, but if you make the archive arbitrarily, virus codes can still be found somewhere.
\(\quad\)Here comes your task (formally): design a 01 string that contains all your resources (their occurrences can overlap), but none of the virus codes. To make your software smaller in size, the string should be as short as possible.

Input

\(\quad\)There will be at most 10 test cases, each begins with two integers in a single line: n and m (2 <= n <= 10, 1 <= m <= 1000). The next n lines contain the resources, one in each line. The next m lines contain the virus codes, one in each line. The resources and virus codes are all non-empty 01 strings without spaces inside. Each resource is at most 1000 characters long. The total length of all virus codes is at most 50000. The input ends with n = m = 0.

Output

\(\quad\)For each test case, print the length of shortest string.

Sample Input

2 2
1110
0111
101
1001
0 0

Sample Output

5

题意

\(\quad\)就是给你\(n\)个需要的串和\(m\)个病毒串,最后让你构造一个字符串,包含所有需要的串,不包括任何病毒串。

思路

\(\quad\)先讲\(n+m\)个串全部插入ac自动机中,然后去构造\(fail\)指针的时候注意将\(fail\)节点的信息传递给子节点。
\(\quad\)首先容易想到\(dp[i][j]\)表示ac自动机上状态为\(i\),包含需要串的状态为\(j\)时所需要的最少字符串数。但是数据范围\(i<=(略大于)5e4,j<=1024\),会\(MLE\)。
\(\quad\)观察数据范围可以发现\(n<<m\),那么说明,在ac自动机上,无用的节点占大多数,那么就可以找出全部有用的节点,用\(bfs\)求出所有有用节点两两之间的最小距离,然后直接在这些有用的点上跑\(dp\)就可以了,那么可以得到新的\(dp\)方程。
\(\quad\)\(dp[i][j]\)表示到有用节点\(i\),包含需要串的状态为\(j\)时所需要的最少字符长度。
\(\quad\)\(cnt[i]\)表示有用节点\(i\)上包含需要串的状态。
\(\quad\)\(cc[i][j]\)表示从有用节点\(i\)走到有用节点\(j\)需要的最少字符数。
\(\quad\)\(dp[k][j|cnt[k]] = min(dp[k][cnt[k]],dp[i][j]+cc[i][k])\)。
\(\quad\)最后在遍历一遍\(dp[i][mx]\),就可以得到答案。

/***************************************************************> File Name    : a.cpp> Author       : Jiaaaaaaaqi> Created Time : 2019年04月29日 星期一 11时10分00秒***************************************************************/#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pii        pair<int, int>typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 6e4 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;int n, m;
int cas, tol, T;char s[1010];
struct AC {int node[maxn][2], fail[maxn], cnt[maxn], vir[maxn];int root, sz;int newnode() {mes(node[++sz], 0);cnt[sz] = vir[sz] = 0;return sz;}void init() {sz = 0;root = newnode();}void insert(char *s, int f, int id) {int len = strlen(s+1);int rt = root;for(int i=1; i<=len; i++) {int k = s[i]-'0';if(node[rt][k] == 0) {node[rt][k] = newnode();}rt = node[rt][k];}if(f == 1)  cnt[rt] |= (1<<(id-1));else    vir[rt] = 1;}void build() {queue<int> q;while(!q.empty())   q.pop();fail[root] = root;for(int i=0; i<=1; i++) {if(node[root][i] == 0) {node[root][i] = root;} else {fail[node[root][i]] = root;q.push(node[root][i]);}}while(!q.empty()) {int u = q.front();q.pop();vir[u] |= vir[fail[u]];cnt[u] |= cnt[fail[u]];for(int i=0; i<=1; i++) {if(node[u][i] == 0) {node[u][i] = node[fail[u]][i];} else {fail[node[u][i]] = node[fail[u]][i];q.push(node[u][i]);}}}}int dis[maxn], point[500];bool vis[maxn];int cc[500][500], dp[500][1030];void bfs(int st) {queue<int> q;while(!q.empty())   q.pop();for(int i=1; i<=sz; i++)    dis[i] = inf;mes(vis, 0);q.push(point[st]);dis[point[st]] = 0;vis[point[st]] = 1;while(!q.empty()) {int u = q.front();q.pop();for(int i=0; i<=1; i++) {int k = node[u][i];if(vir[k])  continue;if(vis[k])  continue;dis[k] = dis[u]+1;vis[k] = true;q.push(k);}}for(int i=1; i<=tol; i++) {cc[st][i] = dis[point[i]];}}void handle() {tol = 0;point[++tol] = 1;for(int i=1; i<=sz; i++) {if(cnt[i]) {point[++tol] = i;}}for(int i=1; i<=tol; i++) {bfs(i);}//     for(int i=1; i<=tol; i++) {//         for(int j=1; j<=tol; j++) {//             printf("%d%c", cc[i][j], j==tol ? '\n' : ' ');//         }//     }//     for(int i=1; i<=tol; i++) {//         printf("cnt[%d] = %d\n", i, cnt[point[i]]);//     }}int solve() {int mx = (1<<n)-1;for(int i=1; i<=tol; i++) {for(int j=0; j<=mx; j++) {dp[i][j] = inf;}}dp[1][0] = 0;for(int j=0; j<=mx; j++) {for(int i=1; i<=tol; i++) {if(dp[i][j] == inf) continue;// printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);for(int k=1; k<=tol; k++) {if(i == k)  continue;dp[k][j|cnt[point[k]]] = min(dp[k][j|cnt[point[k]]], dp[i][j]+cc[i][k]);}}}int ans = inf;for(int i=1; i<=tol; i++) {ans = min(ans, dp[i][mx]);}return ans;}
} ac;int main() {while(scanf("%d%d", &n, &m), n||m) {ac.init();for(int i=1; i<=n; i++) {scanf("%s", s+1);ac.insert(s, 1, i);}for(int i=1; i<=m; i++) {scanf("%s", s+1);ac.insert(s, 2, i);}ac.build();ac.handle();int ans = ac.solve();printf("%d\n", ans);}return 0;
}

转载于:https://www.cnblogs.com/Jiaaaaaaaqi/p/10789881.html

HDU - 3247 Resource Archiver (AC自动机,状压dp)相关推荐

  1. HDU - 3247 Resource Archiver(AC自动机+状压dp+bfs)

    题目链接:点击查看 题目大意:给出 n 个目标串和 m 个病毒串,要求构造出一个长度最短的,且包含全部 n 个目标串,但是不能包含任意一个病毒串的01字符串,输出其最短长度 题目分析:比较综合的一道题 ...

  2. HDU - 2825 Wireless Password(AC自动机+状压dp)

    题目链接:点击查看 题目大意:给出 m 个匹配串,问长度为 n 的字符串中,至少包含 k 个匹配串(可重叠)的字符串有多少个 题目分析:考虑到n,m,k都特别小,所以可以先用AC自动机将状态关系转移出 ...

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

    题目链接 题意 求至少包含KKK个给定字符串长度为NNN的字符串 思路 把所有可能的字符串建AC自动机,遍历所有节点dp[i][j][k]dp[i][j][k]dp[i][j][k] 表示以节点jjj ...

  4. hdu 6086 -- Rikka with String(AC自动机 + 状压DP)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

  5. hdu 6086 Rikka with String(AC自动机+状压dp)

    题目链接:hdu 6086 Rikka with String 题意: 给你n个只含01的串,和一个长度L,现在让你构造出满足s[i]≠s[|s|−i+1] for all i∈[1,|s|] ,长度 ...

  6. HDU - 3341 Lost's revenge(AC自动机+状压dp)

    题目链接:点击查看 题目大意:给出 n 个模式串,最后给出一个匹配串,问如何重新排列匹配串,可以使得匹配串尽可能多的匹配模式串 题目分析:因为是模式串和匹配串的匹配,所以考虑AC自动机,因为数据范围比 ...

  7. AC自动机+状压dp hdu2825 Wireless Password

    传送门:点击打开链接 题意:有个密码长度为n,现在有m个魔力单词,要求密码中魔力单词的种类数>=k,问这种密码的种类数. 思路:和之前一样,我们会想到AC自动机去压缩状态,把状态给简化.然后我们 ...

  8. P4045-[JSOI2009]密码【AC自动机,状压dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P4045 题目大意 给nnn个字符串,求有多少个长度为lll的字符串包含所有给出的字符串 解题思路 因为nnn很小, ...

  9. 【hdu2825】ac自动机 + 状压dp

    传送门 题目大意: 给你一些密码片段字符串,让你求长度为n,且至少包含k个不同密码片段串的字符串的数量. 题解: 因为密码串不多,可以考虑状态压缩 设dp[i][j][sta]表示长为i的字符串匹配到 ...

最新文章

  1. 智能车竞赛线上比赛部分镜头
  2. OpenCV之CvMat Mat IplImage之间相互转换
  3. oracle层次查询中prior与自上而下、自下而上查询
  4. 7.3.4 异步IO(Asynchronous I/O)
  5. SQL解析在美团的应用
  6. “阿法狗”之父:关于围棋,人类3000年来犯了一个错
  7. HTML 5.1 的 14 个新特性(含使用案例)
  8. oracle脚本加并发,定时执行ORACLE脚本,并发邮件到指定邮箱
  9. 20145326蔡馨熤《计算机病毒》——静态分析(2)
  10. 开源电脑屏幕录制软件Captura源码下载及编译(Win10,VS2022)
  11. ubuntu 实现文本方式和图形方式的转换_word格式怎么转成pdf-pdf转换软件_pdf格式转word工具在线免费转换...
  12. 示波器抓取RC663身份证的天线耦合波形
  13. STM32驱动AD9833模块
  14. Tensorflow系列——Saver的用法
  15. Android通讯录管理遇到的权限问题
  16. 1.TCL/TK脚本学习——入门基础
  17. Dreamweaver CS4 快捷键大全
  18. linux 移动存储设备弹出操作详解
  19. 微分dx、dy是无穷小吗?
  20. 利用硬件机器人实现网络试衣

热门文章

  1. 新东方面试知识点记录
  2. POJ 1502 MPI Maelstrom 最短路
  3. python 图像处理(从安装Pillow开始)
  4. 使用 Arduino 和 LM35 温度传感器监测温度
  5. C语言栈实现逆波兰算法
  6. DHCP|什么是DHCP|DHCP介绍
  7. 3.2 读入两个参数
  8. 微信公众号自动回复加超链接最新可用实现方案
  9. expect 批量修改服务器用户密码
  10. 计划备份mysql数据库