题面:洛谷

题解:

  如果我们对这些小串建出AC自动机,那么我们所求的大串就是要求满足遍历过所有AC自动机上的叶子节点,且经过步数最少的串。如果有多个步数相同的串,要输出字典序最小的串。

  在AC自动机上DP。

  因为我们要求所求串内要出现所有给定小串,而小串个数较少,因此我们考虑状压,然后保存下val[i]表示走到这个点,就可以拥有哪些子串。因为一个非终止节点也可能包含给定小串,因此我们要在建好fail之后,继承一个点x的fail[x]所包含的小串,按编号大小更新即可保证在x被更新之前fail[x]已经被更新。

  设f[i][j]表示在AC自动机的第i个节点上,状态为j的最小代价。

  不知你是否注意到这个状态里没有限制长度和字典序?

  其实这是因为我们可以用bfs解决问题,因为走任意一步的代价都是1,也就是每条边的权值都是1,所以如果我们用bfs的顺序来DP,那么谁先DP到拥有所有串,谁就是代价最小的方案。

  那么怎么保证字典序最小?

  我们只需要在bfs的时候从'a'开始枚举即可。

  

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 610
#define ac 4596
#define inf 2139062143 int n, m, maxn, tmp, head, tail;
int f[AC][ac], q1[AC * ac], q2[AC * ac];
short l1[AC][ac], l2[AC][ac];
int c[AC][], val[AC], fail[AC], go[AC], tot;
char s[AC]; inline void add()
{
int len = strlen(s + ), now = ;
for(R i = ; i <= len; i ++)
{
int v = s[i] - 'A';
if(!c[now][v]) c[now][v] = ++ tot, go[tot] = v;
now = c[now][v];
}
val[now] |= tmp, tmp <<= ;//还是要|= 的,否则要是有多个相同串在同一个节点结束就不好了,,,,
} #define q q1
void build()
{
for(R i = ; i < ; i ++)
if(c[][i]) q[++ tail] = c[][i];
while(head < tail)
{
int x = q[++ head];
for(R i = ; i < ; i ++)
{
if(c[x][i]) fail[c[x][i]] = c[fail[x]][i], q[++ tail] = c[x][i];
else c[x][i] = c[fail[x]][i];
}
}
for(R i = ; i <= tot; i ++) val[i] |= val[fail[i]];
}
#undef q void pre()
{
scanf("%d", &n);
maxn = ( << n) - , tmp = ;
memset(f, , sizeof(f));
for(R i = ; i <= n; i ++) scanf("%s", s + ), add();
} void bfs()
{
head = tail = ;
q1[++ tail] = , q2[tail] = ;
f[][] = ;
while(head < tail)
{
int x = q1[++ head], sta = q2[head];
if(sta == maxn)
{
head = ;
while(x)
{
q1[++ head] = go[x];
int tmp1 = x, tmp2 = sta;
x = l1[tmp1][tmp2], sta = l2[tmp1][tmp2];
}//因为要用2次,但是用了第一次之后x or sta就改变了,所以必须保存到临时变量
for(R i = head; i; i --) printf("%c", q1[i] + 'A');
return ;
}
for(R i = ; i < ; i ++)
{
int v = c[x][i], w = sta | val[v];
if(f[v][w] == inf) //bfs包括了最短和字典序最小
{
q1[++ tail] = v, q2[tail] = w;
f[v][w] = f[x][sta] + ;
l1[v][w] = x, l2[v][w] = sta;
}
}
}
} int main()
{
// freopen("in.in", "r", stdin);
pre();
build();
bfs();
// fclose(stdin);
return ;
}

[HNOI2006]最短母串问题 AC自动机的更多相关文章

  1. [HNOI2006]最短母串问题 --- AC自动机 + 隐式图搜索

    [HNOI2006]最短母串问题 题目描述: 给定n个字符串(S1,S2.....,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,......,Sn)都是T的子串. 输入格式: 第 ...

  2. [BZOJ1195]:[HNOI2006]最短母串(AC自动机+BFS)

    题目传送门 题目描述 给定n个字符串(S1,S2,…,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,…,Sn)都是T的子串. 输入格式 第一行是一个正整数n,表示给定的字符串的个数 ...

  3. [HNOI2006]最短母串问题——AC自动机+状压+bfs环形处理

    Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 32MB Input 第一行是一个正整数n(n< ...

  4. P2322 [HNOI2006]最短母串问题

    P2322 [HNOI2006]最短母串问题 AC自动机+bfs 题目要求:在AC自动机建的Trie图上找到一条最短链,包含所有带结尾标记的点 因为n<12,所以我们可以用二进制保存状态:某个带 ...

  5. BZOJ_1195_[HNOI2006]最短母串_AC自动机+BFS+分层图

    BZOJ_1195_[HNOI2006]最短母串_AC自动机+BFS+分层图 Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2, ...

  6. 【状态压缩dp】1195: [HNOI2006]最短母串

    一个清晰的思路就是状压dp:不过也有AC自动机+BFS的做法 Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T ...

  7. bzoj 1195: [HNOI2006]最短母串 爆搜

    1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 894  Solved: 288[Submit][Status] ...

  8. 2782: [HNOI2006]最短母串

    2782: [HNOI2006]最短母串 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3  Solved: 2[Submit][Status][Web ...

  9. BZOJ 1195: [HNOI2006]最短母串

    1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1346  Solved: 450[Submit][Status ...

随机推荐

  1. ES6 localStorage 类库

    无意中看到的,记录下. 用到了es6语法.支持在js中写构造函数 class CovLocalDB { constructor (name) { this.LS = null this.name = ...

  2. Mybatis传递参数的三种方式

    第一种: Dao层使用@Param注解的方法 VersionBox getVersionByVersionNumAndVersionType(@Param("versionNum" ...

  3. stl源码分析之allocator

    allocator封装了stl标准程序库的内存管理系统,标准库的string,容器,算法和部分iostream都是通过allocator分配和释放内存的.标准库的组件有一个参数指定使用的allocat ...

  4. 180719-Quick-Task 动态脚本支持框架之使用介绍篇

    文章链接:https://liuyueyi.github.io/hexblog/2018/07/19/180719-Quick-Task-动态脚本支持框架之使用介绍篇/ Quick-Task 动态脚本 ...

  5. Nginx内容缓存

    本节介绍如何启用和配置从代理服务器接收的响应的缓存.主要涉及以下内容 - 缓存介绍 启用响应缓存 涉及缓存的NGINX进程 指定要缓存的请求 限制或绕过缓存 从缓存中清除内容 配置缓存清除 发送清除命 ...

  6. 生成dataset的几种方式

    1.常用的方式通过sparksession读取外部文件或者数据生成dataset(这里就不讲了)  注: 生成Row对象的方法提一下:RowFactory.create(x,y,z),取Row中的数据 ...

  7. Python基础灬序列(字符串、列表、元组)

    序列 序列是指它的成员都是有序排列,并且可以通过下标偏移量访问到它的一个或几个成员.序列包含字符串.列表.元组. 字符串 chinese_zodiac = '鼠牛虎兔龙蛇马羊猴鸡狗猪' print(c ...

  8. SVN服务器搭建及客户端配置

    为什么要使用SVN? 在程序的编写过程中,每个程序员都会负责开发一个或多个模块,且开发中会生成很多不同的版本, 这就需要程序员有效的管理代码,在需要的时候可以迅速,准确取出相应的版本. Subvers ...

  9. scrum立会报告+燃尽图(第三周第五次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2286 项目地址:https://coding.net/u/wuyy694 ...

  10. Android开发第二阶段(7)

    今天:对项目的最后总结,宣传给下届学生做准备.为了更好的了解和深入书写本次项目的总结随笔.