[JSOI2009]密码
Description
Input
Output
Sample Input
10 2
hello
world
Sample Output
2
helloworld
worldhello
HINT
一看\(n\)这么小就要状压……我们设\(f[i][j][s]\)表示长度为\(i\),AC自动机上节点为\(j\),出现的字符串的状态为\(s\)的方案数,然后直接枚举转移即可
然后难点就在于如何输出方案
首先42这数字非常妙(生命、宇宙以及任何事情的终极答案)
如果存在一个字符可以任意选的情况,那么答案至少也要为2*26=52,所以这种情况是不存在的
所以就直接爆搜,\(O(n!)\)搜索,然后中间疯狂剪枝就好
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
int x=0,f=1;char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
const int N=1e2;
struct S1{
int trie[N+10][26],fail[N+10],End[N+10];
int root,tot;
void insert(char *s,int ID){
int len=strlen(s),p=root;
for (int i=0;i<len;i++){
if (!trie[p][s[i]-'a']) trie[p][s[i]-'a']=++tot;
p=trie[p][s[i]-'a'];
}
End[p]=1<<ID;
}
void make_fail(){
static int h[N+10];
int head=1,tail=0;
for (int i=0;i<26;i++) if (trie[root][i]) h[++tail]=trie[root][i];
for (;head<=tail;head++){
int Now=h[head];
End[Now]|=End[fail[Now]];
for (int i=0;i<26;i++){
if (trie[Now][i]){
int son=trie[Now][i];
fail[son]=trie[fail[Now]][i];
h[++tail]=son;
}else trie[Now][i]=trie[fail[Now]][i];
}
}
}
}AC;//Aho-Corasick automaton
int work(char *s,char *t){
int lens=strlen(s),lent=strlen(t),Ans=0;
for (int i=0;i<lens;i++){
int res=0,x=i,y=0;
while (x<lens&&y<lent){
if (s[x]!=t[y]) break;
res++,x++,y++;
}
if (x!=lens) continue;
Ans=max(Ans,res);
}
return Ans;
}
ll f[30][N+10][(1<<10)+10];
int pos[15],Len[15],g[15][15],L,n,cnt;
bool vis[15];
char s[15][15];
struct S2{char s[N+10];}A[50];
bool operator <(const S2 &x,const S2 &y){
int lenx=strlen(x.s),leny=strlen(y.s);
if (lenx!=leny) return lenx<leny;
for (int i=0;i<lenx;i++) if (x.s[i]!=y.s[i]) return x.s[i]<y.s[i];
return 0;
}
void dfs(int x,int len){
if (len>L) return;
if (x==n){
static char T[N+10];
for (int i=0;i<Len[pos[0]];i++) T[i]=s[pos[0]][i];
int L=Len[pos[0]];
for (int i=1;i<n;i++){
for (int j=0;j<Len[pos[i]];j++)
T[j+L-g[pos[i-1]][pos[i]]]=s[pos[i]][j];
L+=Len[pos[i]]-g[pos[i-1]][pos[i]];
}
memcpy(A[cnt++].s,T,sizeof(T));
return;
}
for (int i=0,tmp;i<n;i++){
if (!vis[i]){
pos[x]=i,vis[i]=1;
tmp=len+Len[i]-(x?g[pos[x-1]][i]:0);
dfs(x+1,tmp);
pos[x]=0,vis[i]=0;
}
}
}
int main(){
L=read(),n=read();
for (int i=0;i<n;i++){
scanf("%s",s[i]);
Len[i]=strlen(s[i]);
AC.insert(s[i],i);
}
AC.make_fail();
f[0][0][0]=1;
for (int i=0;i<L;i++){
for (int j=0;j<=AC.tot;j++){
for (int s=0;s<1<<n;s++){
if (!f[i][j][s]) continue;
for (int k=0;k<26;k++){
int son=AC.trie[j][k];
f[i+1][son][s|AC.End[son]]+=f[i][j][s];
}
}
}
}
ll Ans=0;
for (int i=0;i<=AC.tot;i++) Ans+=f[L][i][(1<<n)-1];
printf("%lld\n",Ans);
if (Ans>42) return 0;
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
g[i][j]=work(s[i],s[j]);
dfs(0,0);
sort(A,A+cnt);
for (int i=0;i<cnt;i++) printf("%s\n",A[i].s);
return 0;
}
[JSOI2009]密码的更多相关文章
- BZOJ 1559: [JSOI2009]密码( AC自动机 + 状压dp )
建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接 ...
- bzoj1559 [JSOI2009]密码
题目链接:[JSOI2009]密码 我们先看第一问:输出方案数 我们把所有给出来的串丢到AC自动机里面去,然后在建出来的\(trie\)图上跑dp 由于\(n\leq 10\)我们很自然的就想到了状压 ...
- 【BZOJ1559】[JSOI2009]密码(AC自动机,动态规划,搜索)
[BZOJ1559][JSOI2009]密码(AC自动机,动态规划,搜索) 题面 BZOJ 洛谷 题解 首先求方案数显然是构建\(AC\)自动机之后再状压\(dp\),似乎没有什么好讲的. 现在考虑答 ...
- P4045 [JSOI2009]密码
题目 P4045 [JSOI2009]密码 做法 AC自动机+状压+爆搜 建AC自动机是显然的,顺便预处理\(lst_i\)表示\(i\)结点以哪些串结束(二进制) 然后跑状压\(dp[i][j][k ...
- [JSOI2009]密码 [AC自动机]
题面 bzoj luogu 首先看到这题就知道随便暴枚 只要是多项式算法都能过 先常规建AC自动机 注意被别的单词包含的单词没有存在的价值 剩余单词状压 大力dp f[长度][节点编号][状态] \( ...
- BZOJ1559[JSOI2009]密码——AC自动机+DP+搜索
题目描述 输入 输出 样例输入 10 2 hello world 样例输出 2 helloworld worldhello 提示 这题算是一个套路题了,多个串求都包含它们的长为L的串的方案数. 显然是 ...
- JSOI2009 密码 和 JSOI2007 文本生成器 和 ZOJ3545 Rescue the Rabbit
密码 众所周知,密码在信息领域起到了不可估量的作用.对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝试所有可能的字母组合,但这是一项很耗时又容易被发现的工 作.所以,为了获取对方的登陆口令,在 ...
- [BZOJ 1559] [JSOI2009] 密码 【AC自动机DP】
题目链接:BZOJ - 1559 题目分析 将给定的串建成AC自动机,然后在AC自动机上状压DP. 转移边就是Father -> Son 或 Now -> Fail. f[i][j][k] ...
- BZOJ 1559 JSOI2009 密码 状压dp+AC自动机+搜索
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1559 分析: 这个题意真的是很**啊!!!直接说每一个字符串至少出现一次不就好了吗... ...
- [BZOJ1559][JSOI2009]密码(AC自动机)
http://www.lydsy.com/JudgeOnline/problem.php?id=1559 2009年的省选题虽然比起现在简单了不少,但对我来说还是很有挑战性的. 首先对于这种多串匹配问 ...
随机推荐
- vue定义全局变量和全局方法
一.全局引入文件 1.先定义共用组件 common.vue <script type="text/javascript"> // 定义一些公共的属性和方法 const ...
- SPOJ7258
传送门 这题可以参考平衡树求第k大的过程,需要预处理一下从当前节点往下走能走出多少个子串. 原本准备存个图用反向的topsort,发现极为麻烦,看了别人的代码后发现,他们按step大小用了基排,省了很 ...
- Vue中的计算属性和监听器(computed 与 watch)
react中数据是单向绑定的,而vue中数据是双向绑定的.为什么? 在react中,主要是通过setState 去改变state的值:而在vue中,会自动的触发set 与get 改变属性的值. 在vu ...
- hdu1198 Farm Irrigation —— dfs or 并查集
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1198 dfs: #include<cstdio>//hdu1198 dfs #includ ...
- RobotFramework教程使用笔记——RIDE的相关知识及Resources创建关键字文件
RIDE是robotframework的图形操作前端,我们在RIDE上进行测试用例设计和编写测试脚本,并执行自动化测试.下面来全面的认识下这个操作工具. 在右边编辑页面有三大模块,Edit,TextE ...
- Linux系统中10个常用的ps命令总结
Linux作为Unix的衍生操作系统,Linux内建有查看当前进程的工具ps.这个工具能在命令行中使用PS 命令是什么 查看它的man手册可以看到,ps命令能够给出当前系统中进程的快照.它能捕获系统在 ...
- 让Outlook一直保持开启
1.将OutLook.exe注册为服务,让其一直保持开启状态 类似于TaobaoProtect.exe是由TBSecSvc服务启动的 http://stackoverflow.com/question ...
- jquery之extend
jquery的extend方法的用法1. [代码][JavaScript]代码 01<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01// ...
- 重装系统后texstudio拼写检查不工作
重装texstudio还是不行. 后来发现是重装系统后用户名和以前的系统用户明不一样,导致系统盘里的用户文件夹路径不一样.而texstudio的字典存放在用户路径文件夹下 C:\Users\xxx\A ...
- 编译Thrift
按照 https://syslint.com/blog/tutorial/how-to-install-apache-thrift-on-ubuntu-14-04/ 进行, 编译时出现错误 make[ ...