zoukankan      html  css  js  c++  java
  • [BZOJ 1559] [JSOI2009] 密码 【AC自动机DP】

    题目链接:BZOJ - 1559

    题目分析

    将给定的串建成AC自动机,然后在AC自动机上状压DP。

    转移边就是Father -> Son 或 Now -> Fail。

    f[i][j][k] ,表示到了字符串第 i 位,在AC自动机的第 j 个节点上,状态为 k 的方案数。

    状态 k 是一个二进制压缩的,表示已经包含了哪些给定串的整数。

    然后...输出方案....这个太麻烦了...我是从最后状态DFS向前反推。

    另外的问题是我写的AC自动机DP无法正确处理给定串存在串 A 包含串 B 的情况,所以我必须将被其他给定串包含的给定串忽略。

    要去掉所有被其他某个给定串包含的给定串。需要在建完Fail之后从每个节点向Fail一直走到Root,将一路上的所有节点都设定为不是给定串。

    当然要记录一下某个节点沿Fail到Root的路径已经被处理的话就 break。

    我刚开始写的代码只能处理一个串是另一个串前缀或后缀的情况,被包含在中间的情况不能处理,但是仍然在BZOJ AC了。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <queue>
     
    using namespace std;
     
    const int MaxL = 15, MaxM = 15, MaxC = 27, MaxN = 25 + 5, MaxNode = 255 + 5;
     
    typedef long long LL;
     
    int n, m, l, Index, Tot, MT, Top;
     
    LL Ans;
    LL f[MaxN][MaxNode][1024 + 15];
     
    char S[MaxL];
     
    struct Str
    {
        char str[MaxN];
    } Sol[50], DS;
     
    bool Cmp(Str s1, Str s2) 
    {
        for (int i = 0; i < n; ++i)
        {  
            if (s1.str[i] == s2.str[i]) continue;
            return s1.str[i] < s2.str[i];
        }
        return false;
    }
     
    struct Trie
    {
        int Num, ID, c, isStr;
        bool Ed;
        Trie *Child[MaxC], *Fail;
    } TA[MaxNode], *P = TA, *Root, *Zero;
     
    void Insert(char *S, int l) 
    {
        Trie *Now = Root;
        int t;
        for (int i = 1; i <= l; ++i)
        {
            t = S[i] - 'a';
            if (Now -> Child[t] == NULL) 
            {
                ++P; P -> Num = 0; P -> ID = ++Tot; P -> c = t;
                Now -> Child[t] = P;
            }
            Now = Now -> Child[t];
        }
        Now -> isStr = 1;
    }
     
    void Init_AC() 
    {
        Index = 0; Tot = 0;
        Zero = P; //ID : 0
        Root = ++P; Root -> ID = ++Tot; //ID : 1
        for (int i = 0; i < 26; ++i) Zero -> Child[i] = Root;
        Zero -> Fail = NULL;
        for (int i = 0; i < 26; ++i) Root -> Child[i] = NULL;
        Root -> Fail = Zero;
    }
     
    queue<Trie *> Q;
     
    void Build_Fail() 
    {
        while (!Q.empty()) Q.pop();
        Q.push(Root);
        Trie *Now, *Temp;
        while (!Q.empty()) 
        {
            Now = Q.front(); Q.pop();
            for (int i = 0; i < 26; ++i)
            {
                if (Now -> Child[i] == NULL) Now -> Child[i] = Now -> Fail -> Child[i];
                else
                {
                    Now -> Child[i] -> Fail = Now -> Fail -> Child[i];
                    Q.push(Now -> Child[i]);         
                }
            }
        }   
        for (Trie *j = TA; ; ++j)
        {
        	Temp = j -> Fail;
        	while (Temp != NULL && Temp != Root && Temp != Zero)
    		{
    			if (Temp -> Ed) break;
    			Temp -> Ed = true;
    			Temp -> isStr = -1;
    			Temp = Temp -> Fail;		
    		}   
        	if (j == P) break;
        }
        for (Trie *j = TA; ; ++j)
        {
        	if (j -> isStr == 1) j -> Num = ++Index;
        	else j -> Num = 0;
        	if (j == P) break;
        }
    }
     
    void DP() 
    {
        f[0][1][0] = 1;
        MT = (1 << Index) - 1;
        for (int i = 0; i <= n; ++i)
            for (int j = 0; j <= Tot; ++j)
                for (int k = 0; k <= MT; ++k)
                    if (f[i][j][k])
                    {
                        for (int t = 0; t < 26; ++t)
                        {
                            if (TA[j].Child[t] -> Num == 0) f[i + 1][TA[j].Child[t] -> ID][k] += f[i][j][k];
                            else f[i + 1][TA[j].Child[t] -> ID][k | (1 << (TA[j].Child[t] -> Num - 1))] += f[i][j][k];
                        }
                    }
        Ans = 0;
        for (int i = 1; i <= Tot; ++i) Ans += f[n][i][MT];
    }
     
    void DFS(int l, int x, int y, int t) 
    {
        //printf("Begin %d %d %d %c
    ", l, x, y, t + 'a');
        DS.str[l - 1] = 'a' + t;
        if (l == 1)
        {
            Sol[++Top] = DS;
            return;
        }
        for (int i = 1; i <= Tot; ++i)
            if (f[l - 1][i][y] && TA[i].Child[t] -> ID == x) 
            {
                if (i == 1) for (int j = 0; j < 26; ++j) DFS(l - 1, i, y, j);
                else DFS(l - 1, i, y, TA[i].c);
            }
        int yy;
        if (TA[x].Num != 0) 
        {
            yy = y - (1 << (TA[x].Num - 1));
            for (int i = 1; i <= Tot; ++i)
                if (f[l - 1][i][yy] && TA[i].Child[t] -> ID == x) 
                {
                    if (i == 1) for (int j = 0; j < 26; ++j) DFS(l - 1, i, yy, j);
                    else DFS(l - 1, i, yy, TA[i].c);
                }
        }
        //printf("End %d %d %d %c
    ", l, x, y, t + 'a');
    }
     
    void Get_Sol() 
    {
        Top = 0;
        for (int i = 1; i <= Tot; ++i) 
            if (f[n][i][MT]) 
            {
                if (i == 1) 
                {
                    for (int j = 0; j < 26; ++j) 
                        DFS(n, i, MT, j);
                }
                else DFS(n, i, MT, TA[i].c);
            }
    }
     
    int main()
    {
        scanf("%d%d", &n, &m);
        Init_AC();
        Index = 0;
        for (int i = 1; i <= m; ++i) 
        {
            scanf("%s", S + 1);
            l = strlen(S + 1);
            Insert(S, l);
        }
        Build_Fail();
        DP();
        printf("%lld
    ", Ans);
        if (Ans <= 42) 
        {
            Get_Sol();
            sort(Sol + 1, Sol + Ans + 1, Cmp);
            for (int i = 1; i <= Ans; ++i) 
            {
                Sol[i].str[n] = 0;
                printf("%s
    ", Sol[i].str);
            }
        }
        return 0;   
    }
    

      

  • 相关阅读:
    盒子垂直水平居中
    Sahi (2) —— https/SSL配置(102 Tutorial)
    Sahi (1) —— 快速入门(101 Tutorial)
    组织分析(1)——介绍
    Java Servlet (1) —— Filter过滤请求与响应
    CAS (8) —— Mac下配置CAS到JBoss EAP 6.4(6.x)的Standalone模式(服务端)
    JBoss Wildfly (1) —— 7.2.0.Final编译
    CAS (7) —— Mac下配置CAS 4.x的JPATicketRegistry(服务端)
    CAS (6) —— Nginx代理模式下浏览器访问CAS服务器网络顺序图详解
    CAS (5) —— Nginx代理模式下浏览器访问CAS服务器配置详解
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4332383.html
Copyright © 2011-2022 走看看