[BZOJ1559][JSOI2009]密码(AC自动机)
http://www.lydsy.com/JudgeOnline/problem.php?id=1559
2009年的省选题虽然比起现在简单了不少,但对我来说还是很有挑战性的。
首先对于这种多串匹配问题,第一个想到的就应该是AC自动机。
还是老套路,f[i][j]表示走到字符串的第i位,现在在自动机上的第j位时的信息。增加一维n位的压位表示各个串是否都被匹配到了。
但是这里有个问题,如果S1包含了S2,那么我们只需要S1被匹配就能保证S2也被匹配,而不需要在自动机上走到S2的位置。
这样我们预处理的时候先删掉所有被包含的字符串(反正L<=25,N<=10怎样都不会T),然后直接在自动机上跑DP即可。
现在考虑ans<=42的情况,可以发现,这种情况下原串不可能有任何一个自由字母。因为只要存在一个自由字母和一个模式串,则至少存在2*26=52>42种方案。所以对于这种情况我们只需用最暴力的方法DFS穷举所有长度为L且恰好包含了每个模式串的方案并按字典序排序。
这里有一个技巧,border[i][j]表示第i个串后缀和第j个串的前缀中完全匹配的最长的串的长度(也就是KMP中的nxt[]),方便穷举。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mem(a) memset(a,0,sizeof(a))
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; int n,m,L,ch[][],q[],num[],fail[],sz,bor[][],g1,g[],a1,len[],rk[],vis[],del[];
char str[][],a[][];
ll f[][][]; int border(int x,int y){
for (int i=min(len[x],len[y]); i>=; i--){
int flag=;
rep(j,,i-) if (str[x][len[x]-i+j]!=str[y][j]){ flag=; break; }
if (!flag) return i;
}
return ;
} void ins(int x){
int now=;
rep(i,,len[x]-){
int s=str[x][i]-'a';
if (!ch[now][s]) ch[now][s]=++sz;
now=ch[now][s];
}
num[now]=<<(x-);
} void getfail(){
int st=,ed=;
rep(i,,) if (ch[][i]) q[++ed]=ch[][i];
while (st<ed){
int x=q[++st];
rep(i,,)
if (ch[x][i]) q[++ed]=ch[x][i],fail[ch[x][i]]=ch[fail[x]][i];
else ch[x][i]=ch[fail[x]][i];
}
} void dfs(int x){
if (x>m){
a1++; int l=;
rep(i,,g1) rep(j,bor[g[i-]][g[i]],len[g[i]]-) a[a1][++l]=str[g[i]][j];
if (l!=L) a1--; return;
}
rep(i,,n) if (!del[i] && !vis[i]) vis[i]=,g[++g1]=i,dfs(x+),vis[i]=,g1--;
} bool cmp(int x,int y){
rep(i,,L) if (a[x][i]!=a[y][i]) return a[x][i]<a[y][i];
return ;
} bool chk(int x,int y){
rep(i,,len[y]-len[x]){
int j=;
for (; j<len[x]; j++) if ((str[x][j])!=str[y][i+j]) break;
if (j==len[x]) return ;
}
return ;
} void dp(){
int now=; f[][][]=;
rep(i,,L-){
now=now^; mem(f[now]);
rep(j,,sz) rep(k,,(<<n)-)
if (f[now^][j][k])
rep(l,,){
int x=ch[j][l],y=k;
if (num[x]) y|=num[x];
f[now][x][y]+=f[now^][j][k];
}
}
ll ans=; int s=;
rep(i,,n) if (!del[i]) s+=<<(i-);
rep(i,,sz) ans+=f[now][i][s];
printf("%lld\n",ans);
if (ans<=){
dfs(); rep(i,,a1) rk[i]=i;
sort(rk+,rk+a1+,cmp);
rep(i,,a1){ rep(j,,L) putchar(a[rk[i]][j]); puts(""); }
}
} int main(){
freopen("bzoj1559.in","r",stdin);
freopen("bzoj1559.out","w",stdout);
scanf("%d%d",&L,&n); m=n;
rep(i,,n) scanf("%s",str[i]),len[i]=strlen(str[i]);
rep(i,,n) rep(j,,n) bor[i][j]=border(i,j);
rep(i,,n) rep(j,,n) if (len[j]>len[i] && !del[j] && !del[i] && chk(i,j)) del[i]=,m--;
rep(i,,n) if (!del[i]) ins(i);
getfail(); dp();
return ;
}
[BZOJ1559][JSOI2009]密码(AC自动机)的更多相关文章
- BZOJ1559[JSOI2009]密码——AC自动机+DP+搜索
题目描述 输入 输出 样例输入 10 2 hello world 样例输出 2 helloworld worldhello 提示 这题算是一个套路题了,多个串求都包含它们的长为L的串的方案数. 显然是 ...
- BZOJ 1559: [JSOI2009]密码( AC自动机 + 状压dp )
建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接 ...
- [JSOI2009]密码 [AC自动机]
题面 bzoj luogu 首先看到这题就知道随便暴枚 只要是多项式算法都能过 先常规建AC自动机 注意被别的单词包含的单词没有存在的价值 剩余单词状压 大力dp f[长度][节点编号][状态] \( ...
- BZOJ1559 [JSOI2009]密码 【AC自动机 + 状压dp】
题目链接 BZOJ1559 题解 考虑到这是一个包含子串的问题,而且子串非常少,我们考虑\(AC\)自动机上的状压\(dp\) 设\(f[i][j][s]\)表示长度为\(i\)的串,匹配到了\(AC ...
- [BZOJ1559]密码 AC自动机+状压
问题 K: [JSOI2009]密码 时间限制: 1 Sec 内存限制: 64 MB 题目描述 众所周知,密码在信息领域起到了不可估量的作用.对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝 ...
- bzoj1559 [JSOI2009]密码
题目链接:[JSOI2009]密码 我们先看第一问:输出方案数 我们把所有给出来的串丢到AC自动机里面去,然后在建出来的\(trie\)图上跑dp 由于\(n\leq 10\)我们很自然的就想到了状压 ...
- 【BZOJ4327】JSOI2012 玄武密码 AC自动机
[BZOJ4327]JSOI2012 玄武密码 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香 ...
- BZOJ4327 [JSOI2012] 玄武密码 [AC自动机]
题目传送门 玄武密码 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神 ...
- Vijos P1951 玄武密码 (AC自动机)
描述 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. 很多年后,人们终于在 ...
随机推荐
- 基于bootstrap物资管理系统后台模板——后台
链接:http://pan.baidu.com/s/1geKwVMN 密码:0utl
- idea docker 连接 linux 上的 docker
安装插件 Docker插件,首先需要在你的IDEA中安装Docker插件,定位到File-Setting-Plugins后搜索Docker Integration安装 配置Docker服务器,在IDE ...
- 42.Trapping Rain Water---dp,stack,两指针
题目链接:https://leetcode.com/problems/trapping-rain-water/description/ 题目大意:与84题做比较,在直方图中计算其蓄水能力.例子如下: ...
- Machine Learning系列--TF-IDF模型的概率解释
信息检索概述 信息检索是当前应用十分广泛的一种技术,论文检索.搜索引擎都属于信息检索的范畴.通常,人们把信息检索问题抽象为:在文档集合D上,对于由关键词w[1] ... w[k]组成的查询串q,返回一 ...
- PHP解决并发问题的几种实现
对于商品抢购等并发场景下,可能会出现超卖的现象,这时就需要解决并发所带来的这些问题了 在PHP语言中并没有原生的提供并发的解决方案,因此就需要借助其他方式来实现并发控制. 方案一:使用文件锁排它锁 f ...
- 记一次java内存溢出的解决过程
注:本文主要记录这次解决内存溢出问题的过程而不是具体问题. 最近在写一个搜索引擎,使用倒排索引结构进行文档检索,保存索引的基本思想是先将倒排列表保存到内存中一个有序Map里(TreeMap),然后当内 ...
- [tensorflow]的安装
1 pip install 最简单直接的方法,通过pip install安装,命令如下: pip install tensorflow-gpu //安装gpu版tensorflow pip insta ...
- Git & GitHub 学习
学习资料: Git版本控制软件结合GitHub从入门到精通常用命令学习手册:http://www.ihref.com/read-16369.html 官方中文手册:http://git-scm.com ...
- [实战]MVC5+EF6+MySql企业网盘实战(14)——思考
写在前面 从上面更新编辑文件夹,就一直在思考一个问题,之前编辑文件夹名称,只是逻辑上的修改,但是保存的物理文件或者文件夹名称并没有进行修改,这样就导致一个问题,就是在文件或者文件夹修改名称后就会找不到 ...
- Typecho-反序列化漏洞学习
目录 Typecho-反序列化漏洞学习 0x00 前言 0x01 分析过程 0x02 调试 0x03 总结 0xFF 参考 Typecho-反序列化漏洞学习 0x00 前言 补丁: https://g ...