[Usaco2006 Dec] Milk Patterns 产奶的模式 - 后缀自动机

Description

给定一个数字串 \(S\),求出现了 \(k\) 次的子串的最大长度。

Solution

考虑基于 std::map 的 SAM

出现 \(k\) 次的条件就是要求 \(endpos\) 集合的大小 \(\ge k\)

于是我们在满足这个条件的所有节点的 \(len\) 中取最大即可

#include 
using namespace std;
const int N = 200005;
struct SAM {
    int len[N], fa[N], ind, last;
    map ch[N];
    int t[N], a[N], cnt[N], f[N];
    SAM() { ind = last = 1; }
    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;
                ch[tmp] = ch[q];
                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 calcEndpos() {
        memset(t, 0, sizeof t);
        for(int i=1; i<=ind; i++) t[len[i]]++;
        for(int i=1; i<=ind; i++) t[i]+=t[i-1];
        for(int i=1; i<=ind; i++) a[t[len[i]]--]=i;
        for(int i=ind; i>=1; --i) cnt[fa[a[i]]]+=cnt[a[i]];
        cnt[1] = 0;
    }
    int solve(int k)
    {
        int ans=0;
        for(int i=1;i<=ind;i++)
        {
            if(cnt[i]>=k) ans=max(ans,len[i]);
        }
        return ans;
    }
} sam;

int main() {
    ios::sync_with_stdio(false);
    int n,k,t;
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>t;
        sam.extend(t);
    }
    sam.calcEndpos();
    cout<

你可能感兴趣的:([Usaco2006 Dec] Milk Patterns 产奶的模式 - 后缀自动机)