1. 程式人生 > 實用技巧 >[板子]字串-KMP與AC自動機

[板子]字串-KMP與AC自動機

KMP

暴跳next

luogu3375

#include <bits/stdc++.h>

const int N = 1e6 + 30; 

int pos;
int lena;
int lenb;
int nx[N];
char a[N];
char b[N];


int main() 
{
    std::cin >> a>> b;
    lena = std::strlen(a);
    lenb = std::strlen(b);
    for (int i = 1; i < lenb; ++i)
    {
        while (pos != 0 && b[pos] != b[i]) 
            pos = nx[pos];
        if (b[pos] == b[i]) 
            ++pos;
        nx[i + 1] = pos;
    }
    pos = 0;
    for (int i = 0; i < lena; ++i)
    {
        while (pos != 0 && b[pos] != a[i])
            pos = nx[pos];
        if (b[pos] == a[i]) 
            ++pos;
        if (pos == lenb)
            printf ("%d\n", i - lenb + 2);
    }
    for (int i = 1; i <= lenb; ++i)
        printf ("%d ", nx[i]);
    printf ("\n");
    return 0;
}

AC自動機

tire樹上暴跳fail

詳細學習請搜尋yyb部落格,講的很好

luogu3796

#include <bits/stdc++.h>

const int N = 1000000 + 30;

int n;
int tot;
std::string s, str[N];

struct AC
{
    int fail;
    int end;
    int vis[28];
}a[N];

struct NODE
{
    int num;
    int tot;
}ans[N];

bool operator <(NODE x, NODE y)
{
    if (x.tot != y.tot)
        return x.tot > y.tot;
    else 
        return x.num < y.num;
}

inline void init(int num)
{
    std::memset(a[num].vis, 0, sizeof(a[num].vis));
    a[num].fail = 0;
    a[num].end = 0;
}

inline void Insert(int num, std::string strr)
{
    int now = 0;
    int len = strr.size();
    for (int i = 0; i < len; ++i)
    {
        if (a[now].vis[strr[i] - 'a'] == 0)
        {
            a[now].vis[strr[i] - 'a'] = ++tot;
            init(tot);
        }
        now = a[now].vis[strr[i] - 'a'];
    }
    a[now].end = num;
}

inline void Work_Fail()
{
    int now = 0;
    std::queue < int > q;
    for (int i = 0; i < 26; ++i)
    {
        if (a[now].vis[i] != 0)
        {
            a[a[now].vis[i]].fail = 0;
            q.push(a[now].vis[i]);
        }
    }
    while (!q.empty())
    {
        now = q.front();
        q.pop();
        for (int i = 0; i < 26; ++i)
        {
            if (a[now].vis[i] != 0)
            {
                a[a[now].vis[i]].fail = a[a[now].fail].vis[i];
                q.push(a[now].vis[i]);
            }
            else
                a[now].vis[i] = a[a[now].fail].vis[i];
        }    
    }
}

inline void Work_Ans(std::string strr)
{
    int now = 0;
    int len = strr.size();
    for (int i = 0; i < len; ++i)
    {
        now = a[now].vis[strr[i] - 'a'];
        for (int t = now; t != 0; t = a[t].fail)
            ++ans[a[t].end].tot;
    }
}

int main() 
{
    while (37373737)
    {
        std::cin >> n;
        if (n == 0)
            return n;
        tot = 0;
        init(0);
        for (int i = 1; i <= n; ++i)
        {
            std::cin >> str[i];
            ans[i] = (NODE){i, 0};
            Insert(i, str[i]);
        }
        Work_Fail();
        std::cin >> s;
        Work_Ans(s);
        std::sort(&ans[1], &ans[n + 1]);
        std::cout << ans[1].tot<< std::endl<< str[ans[1].num]<<std::endl;
        for (int i = 2; i <= n; ++i)
            if (ans[i].tot == ans[i - 1].tot)
                std::cout << str[ans[i].num]<<std::endl;
            else break;
    }
}

luogu3808

#include <bits/stdc++.h>

const int N = 1000000 + 30;

int n;
int tot;
std::string s;

struct AC
{
    int fail, end, vis[28];
}a[N];

inline void Insert(std::string str)
{
    int now = 0;
    int len = str.size();
    for (int i = 0; i < len; ++i)
    {
        if (a[now].vis[str[i] - 'a'] == 0)
            a[now].vis[str[i] - 'a'] = ++tot;    
        now = a[now].vis[str[i] - 'a'];
    }
    ++a[now].end;
}

inline void Work_Fail()
{
    int now = 0;
    std::queue < int > q;
    for (int i = 0; i < 26; ++i)
    {
        if (a[now].vis[i] != 0)
        {
            a[a[now].vis[i]].fail = 0;
            q.push(a[now].vis[i]);
        }
    }
    while (!q.empty())
    {
        now = q.front();
        q.pop();
        for (int i = 0; i < 26; ++i)
        {
            if (a[now].vis[i] != 0)
            {
                a[a[now].vis[i]].fail = a[a[now].fail].vis[i];
                q.push(a[now].vis[i]);
            }
            else
                a[now].vis[i] = a[a[now].fail].vis[i];
        }    
    }
}

int Work_Ans(std::string str)
{
    int now = 0, ans = 0;
    int len = str.size();
    for (int i = 0; i < len; ++i)
    {
        now = a[now].vis[str[i] - 'a'];
        for (int t = now; t != 0 && a[t].end != -1; t = a[t].fail)
        {
            ans += a[t].end;
            a[t].end = -1;
        }
    }
    return ans;
}

int main() 
{
    std::cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        std::cin >> s;
        Insert(s);
    }    
    Work_Fail();
    std::cin >> s;
    printf ("%d\n", Work_Ans(s));
    return 0;
}