1. 程式人生 > >BZOJ 1212 [HNOI2004]L語言 【AC自動機 + 背包】

BZOJ 1212 [HNOI2004]L語言 【AC自動機 + 背包】

har trie 公共前綴 語言 const highlight 復雜度 題解 end

題目鏈接【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自動機 + 背包】