码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2017-10-01 20:33:40      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:bsp   return   复杂   highlight   main   查询   else   node   for   

题目链接【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;
}

  

 

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

标签:bsp   return   复杂   highlight   main   查询   else   node   for   

原文地址:http://www.cnblogs.com/pealicx/p/7617694.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!