SPOJ - NSUBSTR 后缀自动机板子

SPOJ - NSUBSTR

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PII pair<int, int>
#define PLI pair<LL, int>
#define PDD pair<double,double>
#define ull unsigned long long
using namespace std;

const int N = 250000 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;

int n, ans[N];
char s[N];

struct SuffixAutomaton {
    int last, cur, cnt, ch[N<<1][26], id[N<<1], fa[N<<1], dis[N<<1], sz[N<<1], c[N];
    SuffixAutomaton() {cur = cnt = 1;}
    void init() {
        for(int i = 1; i <= cnt; i++) {
            memset(ch[i], 0, sizeof(ch[i]));
            sz[i] = c[i] = dis[i] = fa[i] = 0;
        }
        cur = cnt = 1;
    }
    void extend(int c, int id) {
        last = cur; cur = ++cnt;
        int p = last; dis[cur] = id;
        for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = cur;
        if(!p) fa[cur] = 1;
        else {
            int q = ch[p][c];
            if(dis[q] == dis[p]+1) fa[cur] = q;
            else {
                int nt = ++cnt; dis[nt] = dis[p]+1;
                memcpy(ch[nt], ch[q], sizeof(ch[q]));
                fa[nt] = fa[q]; fa[q] = fa[cur] = nt;
                for(; ch[p][c]==q; p=fa[p]) ch[p][c] = nt;
            }
        }
        sz[cur] = 1;
    }
    void getSize(int n) {
        for(int i = 1; i <= cnt; i++) c[dis[i]]++;
        for(int i = 1; i <= n; i++) c[i] += c[i-1];
        for(int i = cnt; i >= 1; i--) id[c[dis[i]]--] = i;
        for(int i = cnt; i >= 1; i--) {
            int p = id[i];
            sz[fa[p]] += sz[p];
        }
    }
    void solve() {
        for(int i = 2; i <= cnt; i++) {
            ans[dis[i]] = max(ans[dis[i]], sz[i]);
        }
        for(int i = n-1; i >= 1; i--) ans[i] = max(ans[i], ans[i+1]);
        for(int i = 1; i <= n; i++) printf("%d\n", ans[i]);
    }
} sam;

int main() {
    scanf("%s", s + 1);
    n = strlen(s + 1);
    for(int i = 1; i <= n; i++)
        sam.extend(s[i]-‘a‘, i), ans[i] = 0;
    sam.getSize(n);
    sam.solve();
    return 0;
}

/*
*/

原文地址:https://www.cnblogs.com/CJLHY/p/9817451.html

时间: 2024-10-11 11:48:24

SPOJ - NSUBSTR 后缀自动机板子的相关文章

SPOJ LCS 后缀自动机找最大公共子串

这里用第一个字符串构建完成后缀自动机以后 不断用第二个字符串从左往右沿着后缀自动机往前走,如能找到,那么当前匹配配数加1 如果找不到,那么就不断沿着后缀树不断往前找到所能匹配到当前字符的最大长度,然后将cur节点转移到当前节点即可,再把答案加1 记住不断更新所能得到的最大值 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using

后缀自动机板子

后缀自动机 是什么? 博主不想写反正没人看 直接去\(hihocoder\) 1 2 模板 # include <bits/stdc++.h> # define IL inline # define RG register # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; template <class Int> IL void Input(RG Int &a

后缀自动机 板子

后缀自动机 并没有搞的很清楚,凭着当前的理解胡乱bb两句得了,内容存在误导,请仔细甄别. endpos集合 每个子串结尾的位置集合. 本质相同 endpos相等的子串集合 然后这个本质不同的集合构成自动机的状态. \(substr(i)\),状态\(i\)包含的子串集合 \(len(i)\),状态\(i\)包含的最长子串 性质:状态\(i\)包含的子串是最长子串长度连续的一段后缀. 后缀连接(\(parent\)边) 状态\(i\)最小子串的后缀为什么不在里面呢? 因为在别的地方出现了后缀,被分

spoj LCS 后缀自动机

链接:http://www.spoj.com/problems/LCS/ 题意两串LCS 确实没什么好说的,第一次编嘛.把网上的教程斗翻出来看一遍就好了. 另发现,百度内部用户交流使用的图片在百度快照中看得到. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 2510000 #define M

【SPOJ -NSUBSTR】Substrings 【后缀自动机+dp】

题意 给出一个字符串,要你找出所有长度的子串分别的最多出现次数. 分析 我们建出后缀自动机,然后预处理出每个状态的cnt,cnt[u]指的是u这个状态的right集合大小.我们设f[len]为长度为len的子串的最多出现次数.我们对于自动机的每个状态都更新f,f[st[u].len]=max(f[st[u].len],cnt[u]).然后这样更新完以后,可以神奇的dp一下.f[len]=max(f[len],f[len+1]).想想为什么? 1 #include <cstdio> 2 #inc

【SPOJ】8222. Substrings(后缀自动机)

http://www.spoj.com/problems/NSUBSTR/ 题意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值.求F(1)..F(Length(S)) 这题做法: 首先建立字符串的后缀自动机. 因为自动机中的每个状态都代表一类子串前缀,且任意状态的最长的|max|所对应的子串是唯一的. 所以我们算出每个子串(即找到的状态是end态),他们的right值为++(即保证长度为当前子串的出现次数为1),然后自底向上在parent树中更新right值(pare

SPOJ 1812 Longest Common Substring II(后缀自动机)

[题目链接] http://www.spoj.com/problems/LCS2/ [题目大意] 求n个串的最长公共子串 [题解] 对一个串建立后缀自动机,剩余的串在上面跑,保存匹配每个状态的最小值, 取最小值中的最大值即可.由于跑的地方只记录了匹配结尾的状态, 所以还需要更新parent树上的状态,既然匹配到了子节点, 那么parent树链上的值就都能够取到l, 一开始给每个不同状态按照l从小到大分配储存地址, 这样,我们就可以从匹配长度最长的开始更新parent树的情况. [代码] #inc

spoj 1811 LCS - Longest Common Substring (后缀自动机)

spoj 1811 LCS - Longest Common Substring 题意: 给出两个串S, T, 求最长公共子串. 限制: |S|, |T| <= 1e5 思路: dp O(n^2) 铁定超时 后缀数组 O(nlog(n)) 在spoj上没试过,感觉也会被卡掉 后缀自动机 O(n) 我们考虑用SAM读入字符串B; 令当前状态为s,同时最大匹配长度为len; 我们读入字符x.如果s有标号为x的边,那么s=trans(s,x),len = len+1; 否则我们找到s的第一个祖先a,它

spoj 1812 LCS2 - Longest Common Substring II (后缀自动机)

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS差不多的做法 把其中一个A建后缀自动机 考虑一个状态s, 如果A之外的其他串对它的匹配长度分别是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1]