[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自动机)
描述 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. 很多年后,人们终于在 ...
随机推荐
- Java 注解全面解析
1.基本语法 注解定义看起来很像接口的定义.事实上,与其他任何接口一样,注解也将会编译成class文件. @Target(ElementType.Method) @Retention(Retentio ...
- c++刷题(6/100)最长上升子序列
题目一:区间子数组个数 给定一个元素都是正整数的数组A ,正整数 L 以及 R (L <= R). 求连续.非空且其中最大元素满足大于等于L 小于等于R的子数组个数. 例如 : 输入: A = ...
- Linux下的压缩解压缩
Linux下最常用的打包程序就是tar了,使用tar程序打出来的包我们常称为tar包,tar包文件的命令通常都是以.tar结尾的.生成tar包后,就可以用其它的程序来进 行压缩了,所以首先就来讲讲t ...
- 一款线程安全、基本功能齐全的STL
MiniSTL 目前正在完成一个STL,主要想通过该项目锻炼C++编程.模板编程.熟悉STL.锻炼数据结构和算法能力. 项目的目标是实现STL的几大构件+线程安全.项目过程中主要参考SGI STL源码 ...
- Linux系统调用、新增系统调用方法【转】
转自:http://blog.chinaunix.net/uid-25374603-id-3401045.html 说明: 系统调用是内核和应用程序间的接口,应用程序要访问硬件设备和其他操作系统资源, ...
- Deep Learning基础--机器翻译BLEU与Perplexity详解
前言 近年来,在自然语言研究领域中,评测问题越来越受到广泛的重视,可以说,评测是整个自然语言领域最核心和关键的部分.而机器翻译评价对于机器翻译的研究和发展具有重要意义:机器翻译系统的开发者可以通过评测 ...
- 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树
题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...
- C++的一大误区——深入解释直接初始化与复制初始化的区别
转自:http://blog.csdn.net/ljianhui/article/details/9245661 不久前,在博客上发表了一篇文章——提高程序运行效率的10个简单方法,对于其中最后一 ...
- 服务器或普通PC裸机安装 ESXI6.5
ESXI :安装包 http://pan.baidu.com/s/1c2gM0Xq (包含注册机和其他套件,驱动打包工具) ESXI 6.5 在服务器安装比较方便,一般intel 的网卡都没多大问题, ...
- OpenCV3学习笔记
http://blog.csdn.net/u010429424/article/details/73691001 http://blog.csdn.net/zhaoxfxy/article/detai ...