[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;
}

原文地址:https://www.cnblogs.com/Wolfycz/p/10486372.html

时间: 2024-08-30 17:30:12

[JSOI2009]密码的相关文章

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

建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接暴搜答案. 数据范围很小, 可以AC(复杂度懒得算了....) ------------------------------------------------------------------------------------------------ #include<cstdio> #in

bzoj1559 [JSOI2009]密码

题目链接:[JSOI2009]密码 我们先看第一问:输出方案数 我们把所有给出来的串丢到AC自动机里面去,然后在建出来的\(trie\)图上跑dp 由于\(n\leq 10\)我们很自然的就想到了状压 记\(dp[i][j][sta]\)表示原串匹配到了第\(i\)位,在AC自动机里走到了第\(j\)个节点,已经出现了\(sta\)个单词(压缩状态)的方案数 注意到如果有两个串\(s_i\)和\(s_j\)满足\(s_i\)是\(s_j\)的子串,那么我们所构建的串并不一定必须要有\(s_i\)

[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的位置. 这样我们预处

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

问题 K: [JSOI2009]密码 时间限制: 1 Sec  内存限制: 64 MB 题目描述 众所周知,密码在信息领域起到了不可估量的作用.对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝试所有可能的字母组合,但这是一项很耗时又容易被发现的工 作.所以,为了获取对方的登陆口令,在暴力破解密码之前,必须先做大量的准备工作.经 过情报的搜集,现在得到了若干有用信息,形如: “我观察到,密码中含有字符串***.” 例如,对于一个10位的密码以及观察到的字符串hello与world,可能的密

密码算法详解——AES

0 AES简介 美国国家标准技术研究所在2001年发布了高级加密标准(AES).AES是一个对称分组密码算法,旨在取代DES成为广泛使用的标准. 根据使用的密码长度,AES最常见的有3种方案,用以适应不同的场景要求,分别是AES-128.AES-192和AES-256.本文主要对AES-128进行介绍,另外两种的思路基本一样,只是轮数会适当增加. 1 算法流程 AES加解密的流程图如下: AES加密过程涉及到4种操作:字节替代(SubBytes).行移位(ShiftRows).列混淆(MixCo

linux 本地账号密码无法登陆,一直返回 登陆的login界面

登陆redhat一直是返回login,账号和密码没错 通过ssh crt类的软件远程连接系统 然后更改文件   vi /etc/pam.d/login 把 :session required /lib/security/pam_limits.so 更改为:session required /lib64/security/pam_limits.so wq保存

凯撒密码、GDP格式化输出、99乘法表

1凯撒密码加密plaincode=input('请输入明文:')print('密文:',end='')for i in plaincode:print(chr(ord(i)+3),end='') 2.国家名称 GDP总量(人民币亿元) 中国 ¥765,873.4375澳大利亚 ¥ 78,312.4375 print('国家名称 GDP总量(人民币亿元)')print('{0:''<12}¥{1:''>10,.2f}'.format('中国',765873.4375))print('{0:''&

洛谷 P1079 Vigen&#232;re 密码 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1079 题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为 南军所广泛使用. 在密码学中,我们称需要加密的信息为明文,用 M 表示:称加密后的信息为密文,用 C 表示:而密钥是一种

Mysql的更改密码

检查mysql的服务是否能开启,保证mysql的服务能正常开启,进行一下步骤 第一步:将你的Mysql解压到C盘根目录 第二步:(解压后进入目录,找到install.bat文件,用Ediplus打开,找到 --install mysql 和 net start mysql,两个mysql必须一样)进入cmd命令,没有配置环境变量的需要手动切换到mysql\bin的目录下cd命令进入 第三步:使用命令登陆mysql(mysql -localhost -u root),输入原始密码. 第四步: my