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

    题面

    bzoj
    luogu

    首先看到这题就知道随便暴枚
    只要是多项式算法都能过
    先常规建AC自动机
    注意被别的单词包含的单词没有存在的价值
    剩余单词状压

    大力dp f[长度][节点编号][状态]
    (ans = sum f[m][i][S])
    这里把题面的l换成m了 表示密码长度

    如果方案数小于等于42的话
    说明这个密码是给定词拼成的 不会有自由字母
    那么就逆向找到转移到它的状态 记录密码就好啦

    注意比较那里原来写的是
    if(x.s[i] > y.s[i]) return 1;
    显然这样是不行的啊qvq

    #include <cmath>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <complex>
    #include <ctime>
    #include <vector>
    #include <queue>
    #include <bitset>
    #define mp(x, y) make_pair(x, y)
    using namespace std;
    const int N = 12;
    const int M = 102;
    const int Sig = 26;
    int m, n, acsize, vsize, S;
    int en[N], c[M], val[M];
    long long ans, f[26][M][(1 << 10) + 5];
     
    struct STR{
        char s[30];
        void print(){s[m + 1] = ''; printf("%s
    ", s + 1);}
        friend bool operator <(STR x, STR y){
            for(int i = 1; i <= m; ++i)
                if(x.s[i] != y.s[i]) return x.s[i] > y.s[i];
            return 0;
        }//大于 
    }stk;
    vector<STR> str;
     
    struct AC{
        int ch[M][Sig], fail[M];
        queue<int> que;
        void ins(char* ss, int id){
            int now = 0, len = strlen(ss + 1);
            for(int i = 1, cc; i <= len; ++i){
                cc = ss[i] - 'a';
                if(!ch[now][cc]) ch[now][cc] = ++acsize;
                now = ch[now][cc]; c[now] = cc;
            }
            en[id] = now, val[now] = 1;
        }
        void build(){
            int now = 0;
            for(int i = 0; i < Sig; ++i) if(ch[0][i]) que.push(ch[0][i]);
            while(!que.empty()){
                int fro = que.front(); que.pop();
                for(int i = 0; i < Sig; ++i){
                    if(ch[fro][i]) fail[ch[fro][i]] = ch[fail[fro]][i], que.push(ch[fro][i]);//!!
                    else ch[fro][i] = ch[fail[fro]][i];
                }
            }
            for(int i = 0; i <= acsize; ++i) val[fail[i]] = 0;
            for(int i = 0; i <= acsize; ++i) if(val[i])
                val[i] = (1 << vsize), ++vsize;
            S = (1 << vsize) - 1;
        }
        void DP(){ 
            f[0][0][0] = 1;
            for(int i = 0; i < m; ++i)
                for(int j = 0; j <= acsize; ++j)
                    for(int k = 0; k <= S; ++k) if(f[i][j][k]){  
            for(int t = 0; t < Sig; ++t){
                f[i + 1][ch[j][t]][k | val[ch[j][t]]] += f[i][j][k];
                  //  printf("%d %d %d %lld
    ", i, j, k, f[i + 1][ch[j][t]][k | val[ch[j][t]]]);
            }
                    }
        }
    }ac;
     
    void dfs(int x, int cur, int y, int z){
        stk.s[x] = z + 'a';
        if(x == 1){str.push_back(stk); return ;}
        for(int i = 0; i <= acsize; ++i)
            if(f[x - 1][i][y] > 0 && ac.ch[i][z] == cur)
                dfs(x - 1, i, y, c[i]);
        if(val[cur])
            for(int i = 0; i <= acsize; ++i)
                if(f[x - 1][i][y ^ val[cur]] > 0 && ac.ch[i][z] == cur)
                    dfs(x - 1, i, y ^ val[cur], c[i]);
    }
     
    int main(){
        scanf("%d%d", &m, &n);
        char ss[N];
        for(int i = 1; i <= n; ++i){
            scanf("%s", ss + 1);
            ac.ins(ss, i);
        }
        ac.build();
        ac.DP();
         
        for(int i = 0; i <= acsize; ++i)
            ans += f[m][i][S];
        printf("%lld
    ", ans);
        if(ans > 42) return 0;
         
        for(int i = 0; i <= acsize; ++i)
            if(f[m][i][S]) dfs(m, i, S, c[i]);
        sort(str.begin(), str.end());
        while(!str.empty()){
            (str.back()).print(); str.pop_back();
        }
        return 0;   
    }
    
    
  • 相关阅读:
    main方法为什么一定是Public static void
    DOS下编译运行小应用程序
    HelloWorld
    MySQL INFORMATION_SCHEMA 使用(转)
    MySQL int(M)的意义(转)
    Mysql 字符串类型及大小写
    使用Zookeeper 实现选主从或者分布式锁
    记一次CountDownLatch引发的问题
    Mysql恢复部分数据
    记一次Java内存性能分析
  • 原文地址:https://www.cnblogs.com/hjmmm/p/10693049.html
Copyright © 2011-2022 走看看