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自动机)的更多相关文章

  1. BZOJ1559[JSOI2009]密码——AC自动机+DP+搜索

    题目描述 输入 输出 样例输入 10 2 hello world 样例输出 2 helloworld worldhello 提示 这题算是一个套路题了,多个串求都包含它们的长为L的串的方案数. 显然是 ...

  2. BZOJ 1559: [JSOI2009]密码( AC自动机 + 状压dp )

    建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接 ...

  3. [JSOI2009]密码 [AC自动机]

    题面 bzoj luogu 首先看到这题就知道随便暴枚 只要是多项式算法都能过 先常规建AC自动机 注意被别的单词包含的单词没有存在的价值 剩余单词状压 大力dp f[长度][节点编号][状态] \( ...

  4. BZOJ1559 [JSOI2009]密码 【AC自动机 + 状压dp】

    题目链接 BZOJ1559 题解 考虑到这是一个包含子串的问题,而且子串非常少,我们考虑\(AC\)自动机上的状压\(dp\) 设\(f[i][j][s]\)表示长度为\(i\)的串,匹配到了\(AC ...

  5. [BZOJ1559]密码 AC自动机+状压

    问题 K: [JSOI2009]密码 时间限制: 1 Sec  内存限制: 64 MB 题目描述 众所周知,密码在信息领域起到了不可估量的作用.对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝 ...

  6. bzoj1559 [JSOI2009]密码

    题目链接:[JSOI2009]密码 我们先看第一问:输出方案数 我们把所有给出来的串丢到AC自动机里面去,然后在建出来的\(trie\)图上跑dp 由于\(n\leq 10\)我们很自然的就想到了状压 ...

  7. 【BZOJ4327】JSOI2012 玄武密码 AC自动机

    [BZOJ4327]JSOI2012 玄武密码 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香 ...

  8. BZOJ4327 [JSOI2012] 玄武密码 [AC自动机]

    题目传送门 玄武密码 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神 ...

  9. Vijos P1951 玄武密码 (AC自动机)

    描述 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. 很多年后,人们终于在 ...

随机推荐

  1. 【leetcode 简单】第三十六题 最小栈

    设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈. push(x) -- 将元素 x 推入栈中. pop() -- 删除栈顶的元素. top() -- 获取栈顶元素. ...

  2. three.js轨道控制器OrbitControls.js

    https://blog.csdn.net/qq_37338983/article/details/78575333 文章地址

  3. 莫比乌斯反演第二弹 入门 Coprime Integers Gym - 101982B

    题目链接:https://cn.vjudge.net/problem/Gym-101982B 题目大意: 给你(a,b)和(c,d)这两个区间,然后问你这两个区间中互素的对数是多少. 具体思路:和我上 ...

  4. Solaris 系统命令使用说明

    1. 查看进程  --  pgreproot@UA4300D-spa:~# pgrep fmd133095root@UA4300D-spa:~# pgrep -l fmd133095 fmdroot@ ...

  5. 环境变量配错了 command not found

    一般就是忘记在PATH 前面加$ 1.可以用whereis或者which命令查看一下有没有这个命令 具体执行which lswhereis ls 2.系统环境变量导致的问题解决方案: exportPA ...

  6. Perl6多线程1 Thread : new / run

    先看一个小例子: ) { #默认参数 say $name; } sub B(:name($name)) { #默认参数为 any say $name; } A(); A(); B(); B(name ...

  7. redis基础之redis-sentinel(哨兵集群)(六)

    前言 redis简单的主从复制在生产的环境下可能是不行的,因为从服务器只能读不能写,如果主服务器挂掉,那么整个缓存系统不能写入了:redis自带了sentinel(哨兵)机制可以实现高可用. redi ...

  8. curl基于URL的文件传输工具

    简介 cURL是一款开源的基于URL的文件传输工具,支持HTTP.HTTPS.FTP等协议,支持POST.cookie.认证.扩展头部.限速等特性. curl命令用途广泛,比如下载.发送http请求. ...

  9. ASP.NET Core 上传大文件无法接收的问题

    解决办法:在API项目中配置 1. 在 web.config 文件中 <system.webServer>里加入 <security> <requestFiltering ...

  10. WordPress 用户管理插件 WP User Manager

    WP User Manager 是一个较新的用户管理插件,可以在前端实现 用户注册.登录.找回密码.修改个人资料.修改密码等功能,如果你在找这方面的插件,WP User Manager 应该是一个不错 ...