Description

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

Solution

考虑基于 std::map 的 SAM

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

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

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
struct SAM {
    int len[N], fa[N], ind, last;
    map<int,int> 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<<sam.solve(k)<<endl;
}


相关文章:

  • 2021-07-11
  • 2021-11-11
  • 2021-11-04
  • 2022-02-21
  • 2021-08-27
  • 2022-01-19
  • 2022-01-16
  • 2022-01-26
猜你喜欢
  • 2021-12-26
  • 2022-02-08
  • 2021-08-19
  • 2022-02-04
  • 2021-08-05
  • 2021-11-04
  • 2022-12-23
相关资源
相似解决方案