• bzoj1559: [JSOI2009]密码


    题目链接

    bzoj1559: [JSOI2009]密码

    题解

    构造长度为n包含所有模式串的的串,求方案数
    构造AC自动机的trie图
    对于模式串可以装压dp
    设dp[i][j][s]表示位于字符串第i位,位于trie图上的第j个节点,状态为s方案数
    转移边为trie图
    考虑ans<=42的情况,若字符串的某一个位不属于n个字符串中的任何一个
    则至少存在52(2 * 26)种方案。那么答案就是可行串组合直接拼,爆搜
    卡内存能信?

    代码

    /*
    构造长度为n包含所有模式串的的串,求方案数 
    构造AC自动机的trie图 
    对于模式串可以装压dp 
    设dp[i][j][s]表示位于字符串第i位,位于trie图上的第j个节点,状态为s方案数 
    转移边为trie图  
    考虑ans<=42的情况,若字符串的某一个位不属于n个字符串中的任何一个
    则至少存在52(2 * 26)种方案。那么答案就是可行  
    */
    #include<queue> 
    #include<cstdio> 
    #include<cstring> 
    #include<algorithm> 
    #define LL long long
    inline int read() { 
        int x = 0,f = 1;char c = getchar(); 
        while(c < '0'||c > '9')c = getchar(); 
        while(c <= '9' &&c >= '0')x = x * 10 + c - '0',c = getchar(); 
        return x * f; 
    } 
    #define LL long long 
    const int maxn = 57; 
    const int maxNode = 137; 
    char a[maxn][maxn],A[maxn][maxn]; 
    int len[maxn];  
    int l,m,n;
    LL dp[maxn][maxNode][1100 + 7];int sz,bor[maxn][maxn]; 
    int ch[maxNode][31],Snum[maxNode],fail[maxNode]; 
    int border(int x,int y) { //维护一串前与一串后的相同部分,方便搜索 
        for(int i = std::min(len[x],len[y]);i >= 0;-- i) { 
            bool flag = false; 
            for(int j = 1;j <= i;++ j) 
                if(a[x][len[x] - i + j] != a[y][j]) { 
                    flag = true;break;  
                }  
            if(!flag) return i;  
        } 
    }  
    void insert(int x) { 
        int now = 0; 
        for(int i = 1;i <= len[x]; ++ i) { 
            int s = a[x][i] - 'a'; 
            if(!ch[now][s]) ch[now][s] = ++ sz; 
            now = ch[now][s]; 
        } 
        Snum[now] = (1 << (x - 1)); 
    } 
    std::queue<int>que; 
    void getfail() { 
        for(int i = 0;i <= 25;++ i) if(ch[0][i])que.push(ch[0][i]); 
        while(!que.empty()) {
            int now = que.front();que.pop();  
            for(int i = 0;i <= 25;++ i) { 
                if(ch[now][i]) fail[ch[now][i]] = ch[fail[now]][i],que.push(ch[now][i]);
                else ch[now][i] = ch[fail[now]][i]; // 
            } 
        }
    } 
    int del[maxn]; 
    bool check(int x,int y) { 
        for(int i = 0;i < len[y] - len[x] + 1;++ i) { 
            int j = 1; 
            for(;j <= len[x];j ++ )if(a[x][j] != a[y][i + j]) break; 
            if(j == len[x] + 1) return true; 
        } 
        return false; 
    } 
    void unique() { 
        for(int i = 1;i <= n;++ i) for(int j = 1;j <= n;++ j) 	
            if(len[j] > len[i] && !del[j] && !del[i] &&check(i,j)) del[i] = 1,m --;
        for(int i = 1;i <= n;++ i) 
            for(int j = 1;j <= n;++ j) 
                bor[i][j] = border(i,j); 
    } 
    int Atot = 0,Gtot = 0,g[maxn]; 
    bool vis[maxn]; 
    void dfs(int x) { 
        if(x > m) { 
            Atot ++; int t = 0; 
            for(int i = 1;i <= Gtot;++ i) 
                for(int j = bor[g[i - 1]][g[i]] + 1;j <= len[g[i]];++ j) 
                    A[Atot][++ t] = a[g[i]][j]; 
            if(t != l) Atot --;
            return; 
        } 
        for(int i = 1;i <= n;i ++) {  
            if(!del[i] && !vis[i]) { 
                vis[i] = 1; g[++ Gtot] = i;  
                dfs(x + 1);  
                vis[i] = 0;Gtot --; 
            }
        } 
    } 
    bool cmp(int x,int y) { 
        for(int i = 1;i <= l;++ i) if(A[x][i] != A[y][i]) return A[x][i] < A[y][i]; return false;
    } 
    int rk[maxn]; 
    void solve() { 
        dp[0][0][0] = 1; 
        for(int i = 1;i <= l;++ i) { 
            for(int j = 0;j <= sz;++ j)  
                for(int s = 0;s <= (1 << n) - 1;++ s) 
                    if(dp[i - 1][j][s])  
                        for(int x,ss,l = 0;l <= 25;++ l) { 
                            x = ch[j][l]; ss = s;
                            if(Snum[x])ss |= Snum[x];  
                            dp[i][x][ss] += dp[i - 1][j][s]; 
                        } 
        } 
        LL ans = 0,s = 0; 
        for(int i = 1;i <= n;++ i) if(!del[i])s += 1 << (i - 1); 
        for(int i = 0;i <= sz;++ i)ans += dp[l][i][s]; 
        printf("%lld
    ",ans); 
        if(ans <= 42) {
            dfs(1); for(int i = 1;i <= Atot; ++ i)rk[i] = i; 
            std::sort(rk + 1,rk + Atot + 1,cmp); 
            for(int i = 1;i <= Atot;++ i) { 
                for(int j = 1;j <= l;++ j)printf("%c",A[rk[i]][j]); 
                puts(""); 
            }
        } 
    } 
    
    int main() { 
        l = read(),m = read(),n = m; 
        for(int i = 1;i <= m;++ i) 
            scanf("%s",a[i] + 1) , len[i] = strlen(a[i] + 1);  	
        unique(); 
        for(int i = 1;i <= n;++ i) if(!del[i]) insert(i); 
        getfail(); 	
        solve(); 
        return 0;
    } 
     
    
  • 相关阅读:
    SVG
    GML、SVG、VML的比较
    用VS.NET中的测试工具测试ASP.NET程序
    Ajax.NET 初步应用
    解决“未能创建 Mutex”的问题(转)
    .net捕获全局异常并且记录日志、多线程方式发送邮件提醒
    DataTable导出到Excel时身份证号信息自动转换为科学计数法的解决方案
    js三级联动地址选择
    .net通过一般处理程序模拟用户控件数据保持、Ispostback 【第二版将html与ashx文件分开】
    .net通过一般处理程序模拟用户控件数据保持、Ispostback
  • 原文地址:https://www.cnblogs.com/sssy/p/9270208.html
Copyright © 2020-2023  润新知