1. 程式人生 > 實用技巧 >[HDU5769] Substring - 字尾自動機

[HDU5769] Substring - 字尾自動機

Description

給你一個串,問你含某個特定的字元的本質不同子串有多少種。

Solution

\(f[p]\) 表示從結點 \(p\) 沿著轉移邊走能到達的不同合法子串有多少種

設題中要求要走的字母為 \(c\)

對於 \(p + c \to q\)\(f[p] \leftarrow siz(q)\)

對於 \(p+? \to q, ? \neq c\)\(f[p] \leftarrow f[q]\)

其中 \(siz(p)\) 表示 \(p\) 點往後可以轉移到的本質不同子串數目

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
struct SAM
{
    int len[N], ch[N][26], fa[N], ind, last;
    int t[N], a[N], cnt[N], vis[N];
    long long f[N];
    SAM()
    {
        ind = last = 1;
    }
    void init()
    {
        ind = last = 1;
        memset(len,0,sizeof len);
        memset(ch,0,sizeof ch);
        memset(fa,0,sizeof fa);
        memset(t,0,sizeof t);
        memset(a,0,sizeof a);
        memset(cnt,0,sizeof cnt);
        memset(f,0,sizeof f);
        memset(vis,0,sizeof vis);
    }
    inline void extend(int id)
    {
        int cur = (++ ind), p;
        len[cur] = len[last] + 1;
        cnt[cur] = 1;
        for (p = last; p && !ch[p][id]; p = fa[p]) ch[p][id] = cur;
        if (!p) fa[cur] = 1;
        else
        {
            int q = ch[p][id];
            if (len[q] == len[p] + 1) fa[cur] = q;
            else
            {
                int tmp = (++ ind);
                len[tmp] = len[p] + 1;
                for(int i=0; i<26; i++) ch[tmp][i] = ch[q][i];
                fa[tmp] = fa[q];
                for (; p && ch[p][id] == q; p = fa[p]) ch[p][id] = tmp;
                fa[cur] = fa[q] = tmp;
            }
        }
        last = cur;
    }
    void dfs0(int p,char chr)
    {
        vis[p]=1;
        cnt[p]=1;
        for(int i=0;i<26;i++)
        {
            if(ch[p][i])
            {
                if(!vis[ch[p][i]])
                {
                    dfs0(ch[p][i],chr);
                }
                cnt[p]+=cnt[ch[p][i]];
            }
        }
    }
    void dfs(int p,char chr)
    {
        vis[p]=1;
        for(int i=0;i<26;i++)
        {
            if(ch[p][i])
            {
                if(!vis[ch[p][i]])
                {
                    dfs(ch[p][i],chr);
                }
                if(i==chr-'a') f[p]+=cnt[ch[p][i]];
                else f[p]+=f[ch[p][i]];
            }
        }
    }
    void solve(char chr)
    {
        /*for(int i=ind; i>=1; --i)
        {
            for(int j=0; j<26; j++)
            {
                if(ch[i][j])
                {
                    if(j==chr-'a') f[i]+=cnt[ch[i][j]];
                    else f[i]+=f[ch[i][j]];
                }
            }
        }*/
        dfs0(1,chr);
        memset(vis,0,sizeof vis);
        dfs(1,chr);
    }
} sam;

long long solve()
{
    ios::sync_with_stdio(false);
    string str;
    char t;
    cin>>str;
    t=str[0];
    cin>>str;
    sam.init();
    for(int i=0; i<str.length(); i++)
        sam.extend(str[i]-'a');
    sam.solve(t);
    return sam.f[1];
}

signed main()
{
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    for(int i=1;i<=t;i++)
    {
        cout<<"Case #"<<i<<": "<<solve()<<endl;
    }
}