zoukankan      html  css  js  c++  java
  • [BZOJ1559]密码 AC自动机+状压

    问题 K: [JSOI2009]密码

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述

    众所周知,密码在信息领域起到了不可估量的作用。对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝试所有可能的字母组合,但这是一项很耗时又容易被发现的工 作。所以,为了获取对方的登陆口令,在暴力破解密码之前,必须先做大量的准备工作。经 过情报的搜集,现在得到了若干有用信息,形如:

    “我观察到,密码中含有字符串***。”

    例如,对于一个10位的密码以及观察到的字符串hello与world,可能的密码组合为 helloworld与worldhello;而对于6位的密码以及观察到的字符串good与day,可能的 密码组合为gooday。

    有了这些信息,就能够大大地减少尝试的次数了。请编一个程序,计算所有密码组合的 可能。密码中仅可能包含a - z之间的小写字母。

    输入

    输入数据首先输入两个整数L,N,分别表示密码的长度与观察到子串的个数。 

    接下来N行,每行若干个字符,描述了每个观察到的字符串。

    输出

    输出数据第一行为一个整数,代表了满足所有观察条件字符串的总数。

    若这个数字小于等于42,则按字典顺序输出所有密码的可能情况,每行一个,

    否则,只输出满足所有观察条件字符串的总数即可。

    样例输入

    10 2
    hello
    world
    

    样例输出

    2
    helloworld
    worldhello
    

    提示

    对于100%的数据,1<=L<=25,1<=N<=10,每个观察到的字符串长不超过10,并且保 证输出结果小于2^63。

    好久没打AC自动机上的DP了……我怎么什么题都不会做啊.jpg

    这道题是我今天刷到的比较好的一道题……不仅考到了dp,还考到了搜索基本功。

    我们首先考虑:对于串i和j,如果j是i的子串,那么我们根本不用考虑最初单独插入进来的j串,

    因为只要i串存在,j串就一定存在

    那么我们可以在构建出AC自动机之后,把每个节点从fail指针能达到的节点都设为”不是单词节点“,最后再给单词节点重新编号即可。

    那么接下来,我们考虑dp的过程。由于节点数,串数和串长都很小,所以我们考虑状态压缩来解决这个问题。

    我们定义状态数组f[i][j][k]表示当前串长为i,位于j号节点,模式串出现情况为k的方案数。

    (这种"走i步到达j节点”也是AC自动机上的常见套路之一)

    那么我们事先把单词节点对应的串用二进制压好,转移到时候我们只需要这样处理即可:

    f[i+1][rt->ch[u]->id][k|rt->ch[u]->val]+=f[i][j][k]

    这样我们就可以搜出方案数,接下来我们考虑输出小于42的具体方案。

    首先我们可以得到一个性质:若总方案树不超过42,那么最终串一定仅由给定串拼接而成。

    因为如果随机字母可以存在,哪怕只有1个模式串,并且仅有1个随机字母,合法方案数在这种最小情况下也有2×26=52(>42)个

    因此我们只需要用搜索进行一个dp的逆过程,看合法方案由哪个节点转移过来,并且记录一路上经过的字符,最后排序输出即可。

    这真是一道很不错的题目,方式以及套路很经典,对于状压和搜索的应用都很灵活!

    (Ps:我还打了一种利用状压从而不用去重的打法,放在最下面)

    去重版代码见下:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 const int N=12,L=30,K=(1<<10)+10;
     6 typedef long long LL;
     7 short l,n,len[N],bin[N],tot,cnt,num;
     8 char s[N][N];
     9 struct node
    10 {
    11     node *ch[26],*f;short id,st,meaning;
    12     node(){memset(ch,0,sizeof(ch)),st=0,id=++cnt;}
    13 }*null,*root,*q[N*N],*data[N*N];
    14 inline node* newnode()
    15     {node *o=new node();data[cnt]=o;return o;}
    16 inline void add(int x)
    17 {
    18     node *rt=root;register int i,d;
    19     for(i=0;i<len[x];++i)
    20     {
    21         d=s[x][i]-'a';
    22         if(!rt->ch[d])rt->ch[d]=newnode();
    23         rt=rt->ch[d],rt->meaning=d;
    24     }
    25     rt->st=1;
    26 }
    27 inline void get_fail()
    28 {
    29     register int i,hd=1,tl=0;
    30     node *rt,*u;
    31     for(i=0,root->f=root;i<26;++i)
    32         if(root->ch[i])root->ch[i]->f=root,q[++tl]=root->ch[i];
    33         else root->ch[i]=root;
    34     while(hd<=tl)
    35         for(rt=q[hd++],u=rt->f,i=0;i<26;++i)
    36             if(rt->ch[i])rt->ch[i]->f=u->ch[i],q[++tl]=rt->ch[i];
    37             else rt->ch[i]=u->ch[i];
    38     for(i=1;i<=cnt;++i)for(u=data[i]->f;u&&u!=null&&u!=root;u=u->f)u->st=0;
    39     for(i=1;i<=cnt;++i)if(data[i]->st)data[i]->st=++num;
    40     for(i=1;i<=cnt;++i)if(data[i]->st)data[i]->st=bin[num-data[i]->st];
    41 }
    42 LL f[L][N*N][K];
    43 struct sol
    44 {
    45     char s[L];
    46     sol(){memset(s,0,sizeof(s));}
    47     inline void print(){puts(s);}
    48     inline bool operator < (const sol &b) const
    49     {
    50         for(register int i=0;i<l;++i)
    51             if(s[i]!=b.s[i])return s[i]<b.s[i];
    52     }
    53 }str[50],stack;
    54 void dfs(int len,int id,int state,int now)
    55 {
    56     register int i,j,k,st;
    57     stack.s[len-1]=now+'a';
    58     if(len==1){str[++tot]=stack;return;}
    59     for(j=2;j<=cnt;++j)
    60         if(f[len-1][j][state]&&data[j]->ch[now]->id==id)
    61             dfs(len-1,j,state,data[j]->meaning);
    62     if(data[id]->st)
    63         for(st=state^data[id]->st,j=2;j<=cnt;++j)
    64             if(f[len-1][j][st]&&data[j]->ch[now]->id==id)
    65                 dfs(len-1,j,st,data[j]->meaning);
    66 }
    67 inline void get_solution()
    68 {
    69     register int i,j;tot=0;
    70     for(j=2;j<=cnt;++j)
    71         if(f[l][j][bin[num]-1])
    72             dfs(l,j,bin[num]-1,data[j]->meaning);
    73 }
    74 int main()
    75 {
    76     scanf("%d%d",&l,&n);root=newnode();
    77     register int i,j,k,u,v;node *rt;LL ans=0;
    78     bin[0]=1;for(i=1;i<=n;++i)bin[i]=bin[i-1]<<1;
    79     for(i=1;i<=n;++i)scanf("%s",s[i]),len[i]=strlen(s[i]),add(i);
    80     get_fail();
    81     for(i=0,f[0][1][0]=1;i<l;++i)
    82         for(j=0;j<=cnt;++j)
    83             for(rt=data[j],k=0;k<bin[num];++k)
    84                 if(f[i][j][k])for(u=0;u<26;++u)
    85                     f[i+1][rt->ch[u]->id][k|rt->ch[u]->st]+=f[i][j][k];
    86     for(j=1;j<=cnt;++j)ans+=f[l][j][bin[num]-1];
    87     printf("%lld
    ",ans);
    88     if(ans<=42)
    89     {
    90         get_solution();sort(str+1,str+ans+1);
    91         for(i=1;i<=ans;++i)str[i].print();
    92     }
    93 }

    不去重打法:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 const int N=12,L=30,K=(1<<10)+10;
     6 typedef long long LL;
     7 short l,n,len[N],bin[N],cnt,tot,num;
     8 char s[N][N];
     9 struct node
    10 {
    11     node *ch[26],*f,*fa;short id,st,meaning;
    12     node(){memset(ch,0,sizeof(ch)),st=0,id=++cnt;}
    13 }*root,*q[N*N],*data[N*N];
    14 inline node* newnode()
    15     {node *o=new node();data[cnt]=o;return o;}
    16 inline void add(int x)
    17 {
    18     node *rt=root;register int i,d;
    19     for(i=0;i<len[x];++i)
    20     {
    21         d=s[x][i]-'a';
    22         if(!rt->ch[d])rt->ch[d]=newnode();
    23         rt->ch[d]->fa=rt,rt=rt->ch[d],rt->meaning=d;
    24     }
    25     rt->st|=bin[n-x];
    26 }
    27 inline void get_fail()
    28 {
    29     register int i,hd=1,tl=0;
    30     node *rt,*u;root->f=root;
    31     for(i=0;i<26;++i)
    32         if(root->ch[i])
    33             root->ch[i]->f=root,q[++tl]=root->ch[i];
    34         else root->ch[i]=root;
    35     while(hd<=tl)
    36         for(rt=q[hd++],u=rt->f,i=0;i<26;++i)
    37             if(rt->ch[i])
    38                 rt->ch[i]->f=u->ch[i],q[++tl]=rt->ch[i],
    39                 rt->ch[i]->st|=rt->ch[i]->f->st;
    40             else rt->ch[i]=u->ch[i];
    41 }
    42 LL f[L][N*N][K];
    43 struct sol
    44 {
    45     char s[L];
    46     sol(){memset(s,0,sizeof(s));}
    47     inline void print(){puts(s);}
    48     inline bool operator < (const sol &b) const
    49     {
    50         for(register int i=0;i<l;++i)
    51             if(s[i]!=b.s[i])return s[i]<b.s[i];
    52     }
    53 }str[50],stack;
    54 void dfs(int len,int id,int state,int now)
    55 {
    56     register int i,j,k,st;
    57     stack.s[len-1]=now+'a';
    58     if(len==1){str[++tot]=stack;return;}
    59     for(j=2;j<=cnt;++j)
    60         if(f[len-1][j][state]&&data[j]->ch[now]->id==id)
    61             dfs(len-1,j,state,data[j]->meaning);
    62     if(data[id]->st)
    63         for(st=state&(~data[id]->st),j=2;j<=cnt;++j)
    64             if(f[len-1][j][st]&&data[j]->ch[now]->id==id)
    65                 dfs(len-1,j,st,data[j]->meaning);
    66 }
    67 inline void get_solution()
    68 {
    69     register int i,j;tot=0;
    70     for(j=2;j<=cnt;++j)
    71         if(f[l][j][bin[n]-1])
    72             dfs(l,j,bin[n]-1,data[j]->meaning);
    73 }
    74 int main()
    75 {
    76     scanf("%d%d",&l,&n);root=newnode();root->fa=root;
    77     register int i,j,k,u,v;node *rt;LL ans=0;
    78     bin[0]=1;for(i=1;i<=n;++i)bin[i]=bin[i-1]<<1;
    79     for(i=1;i<=n;++i)
    80         scanf("%s",s[i]),len[i]=strlen(s[i]),add(i);
    81     get_fail();
    82     for(i=1,f[0][1][0]=1;i<=l;++i)
    83         for(j=1;j<=cnt;++j)
    84             for(rt=data[j],k=0;k<bin[n];++k)
    85                 if(f[i-1][j][k])for(u=0;u<26;++u)
    86                     f[i][rt->ch[u]->id][k|rt->ch[u]->st]+=f[i-1][j][k];
    87     for(j=1;j<=cnt;++j)ans+=f[l][j][bin[n]-1];
    88     printf("%lld
    ",ans);
    89     if(ans<=42)
    90     {
    91         get_solution();sort(str+1,str+ans+1);
    92         for(i=1;i<=ans;++i)str[i].print();
    93     }
    94 }
  • 相关阅读:
    接口测试基础理论
    Python 接口测试requests.post方法中data与json参数区别
    将博客搬至CSDN
    [设计模式] 设计模式课程(二十)--命令模式(Command)
    [设计模式] 设计模式课程(十三)-- 代理模式
    [设计模式] 设计模式课程(十一)-- 享元模式(Flyweight)
    [设计模式] 设计模式课程(十二)-- 门面模式(Facade)
    [设计模式] 设计模式课程(十七)--组合模式
    [设计模式] 设计模式课程(六)-- 桥接模式
    [设计模式] 读懂UML图
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7514403.html
Copyright © 2011-2022 走看看