BZOJ 1212 [HNOI2004]L语言 【AC自动机 + 背包】

题目链接【http://www.lydsy.com/JudgeOnline/problem.php?id=1212】

题意:给你一些单词,然后给出一个没有标点的文本串S,都是小写字符。现在让你求用给出的单词组成文本串T,求S和T的最长公共前缀。

题解:AC自动机 + 背包,背包dp[i],表示是否能组成长度为【1,i】的前缀,在自动机中维护Len[i],表示第i个节点到根节点的距离,End[i],节点i是否是某个单词的结尾。在查询的时候,我们只需要在对应的Trie上跳就可以了,时间复杂度为x * N*log(N)。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1024 * 1024 + 15;
int dp[maxn];
struct Aho_C
{
    int Next[maxn][26], Fail[maxn], End[maxn], Len[maxn];
    int root, sz;
    int newnode()
    {
        for(int i = 0; i < 26; i++)
            Next[sz][i] = -1;
        End[sz++] = 0;
        return sz - 1;
    }
    void init()
    {
        sz = 0;
        root = newnode();
    }
    void Insert(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0; i < len; i++)
        {
            if(Next[now][buf[i] - 'a'] == -1)
                Next[now][buf[i] - 'a'] = newnode();
            now = Next[now][buf[i] - 'a'];
            Len[now] = i + 1;
        }
        End[now]++;
    }
    void Build()
    {
        queue<int>Q;
        Fail[root] = root;
        for(int i = 0; i < 26; i++)
            if(Next[root][i] == -1)
                Next[root][i] = root;
            else
            {
                Fail[Next[root][i]] = root;
                Q.push(Next[root][i]);
            }
        while( !Q.empty() )
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0; i < 26; i++)
                if(Next[now][i] == -1)
                    Next[now][i] = Next[Fail[now]][i];
                else
                {
                    Fail[Next[now][i]] = Next[Fail[now]][i];
                    Q.push(Next[now][i]);
                }
        }
    }
    void Query(char buf[])
    {
        int len = strlen(buf + 1);
        int now = root;
        for(int i = 1; i <= len; i++)
        {
            dp[i] = 0;
            now = Next[now][buf[i] - 'a'];
            int temp = now;
            int tmp = Len[temp];
            while( temp != root)
            {
                if(End[temp])
                {
                    int pos = i - Len[temp];
                    dp[i] = max(Len[temp] + dp[pos], dp[i]);
                }
                temp = Fail[temp];
            }
        }
    }
} ac;
char buf[maxn * 2];
int main()
{
    int N, M;
    scanf("%d %d", &N, &M);
    ac.init();
    for(int i = 1; i <= N; i++)
    {
        scanf("%s", buf);
        ac.Insert(buf);
    }
    ac.Build();
    for(int i = 1; i <= M; i++)
    {
        scanf("%s", buf + 1);
        ac.Query(buf);
        int len = strlen(buf + 1);
        int ma = 0;
        for(int i = len; i >= 1; i--)
        {
            if(dp[i] == i)
            {
                ma = i;
                break;
            }
        }
        printf("%d\n", ma);
    }
    return 0;
}

  

 

posted @ 2017-10-01 19:56  _Mickey  阅读(139)  评论(0编辑  收藏  举报