【SPOJ】Substrings(后缀自动机)

/*
求right集合大小
然后后缀最大值 

*/
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
#define ll long long
#define M 600010
#define mmp make_pair
using namespace std;
int read()
{
    int nm = 0, f = 1;
    char c = getchar();
    for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
    return nm * f;
}
char s[M];
int ch[M][26], sz[M], ans[M], tim[M], a[M], fa[M], len[M], cnt = 1, lst = 1; 

void insert(int c)
{
    int p = ++cnt, f = lst;
    lst = cnt;
    len[p] = len[f] + 1;
    sz[p] = 1;
    while(f && !ch[f][c]) ch[f][c] = p, f = fa[f];
    if(!f) fa[p] = 1;
    else
    {
        int q = ch[f][c];
        if(len[q] == len[f] + 1) fa[p] = q;
        else
        {
            int nq = ++cnt;
            fa[nq] = fa[q];
            len[nq] = len[f] + 1;
            memcpy(ch[nq], ch[q], sizeof(ch[nq]));
            fa[p] = fa[q] = nq;
            while(f && ch[f][c] == q) ch[f][c] = nq, f = fa[f];
        }
    }
}

int main()
{
    scanf("%s", s + 1);
    int l = strlen(s + 1);
    for(int i = 1; i <= l; i++) insert(s[i] - 'a');
    for(int i = 1; i <= cnt; i++) tim[len[i]]++;
    for(int i = 1; i <= cnt; i++) tim[i] += tim[i - 1];
    for(int i = 1; i <= cnt; i++) a[tim[len[i]]--] = i;
    for(int i = cnt; i >= 1; i--)
    {
        sz[fa[a[i]]] += sz[a[i]];
        ans[len[a[i]]] = max(ans[len[a[i]]], sz[a[i]]);
    }
    for(int i = cnt; i >= 1; i--) ans[i] = max(ans[i], ans[i + 1]);
    for(int i = 1; i <= l; i++) cout << ans[i] << "\n";
    return 0;
}

原文地址:https://www.cnblogs.com/luoyibujue/p/10612613.html

时间: 2024-10-20 09:03:21

【SPOJ】Substrings(后缀自动机)的相关文章

【CF316G3】Good Substrings 后缀自动机

[CF316G3]Good Substrings 题意:给出n个限制(p,l,r),我们称一个字符串满足一个限制当且仅当这个字符串在p中的出现次数在[l,r]之间.现在想问你S的所有本质不同的子串中,有多少个满足所有限制. |S|,|p|<=10^5,n<=10. 题解:比较简单的后缀自动机题,我们先把原串和所有限制串放到一起建一个广义后缀自动机,然后在pre树上统计一下即可得到每个子串在每个限制串中出现了多少次.现在我们想知道原串中有多少满足条件的子串,即我们统计一下所有出现次数符合要求的,

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

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

【POJ3415】Common Substrings 后缀自动机

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42710069 其实我就是觉得原创的访问量比未授权盗版多有点不爽233... 题意: 给两个串,问有多少长度大于等于K的公共子串(位置不同也算一对) 题解: 后缀自动机DP 对第一个串建立后缀自动机,然后做一些预处理, 然后拿第二个串在后缀自动机上跑,到每个节点加一次贡献. 但是这样需要每个点往parent树上跑一遍,会TLE,所以可以加个lazy. 然后代码中有两次运用到拓扑序来从子向父

SPOJ8222 Substrings( 后缀自动机 + dp )

题目大意:给一个字符串S,令F(x)表示S的所有长度为x的子串中,出现次数的最大值.F(1)..F(Length(S)) 建出SAM, 然后求出Right, 求Right可以按拓扑序dp..Right就是某个点到结束状态的路径数, parent树上last的那一条链都是结束状态...然后用Right去更新答案.. spoj卡常数..一开始用DFS就炸了, 改用BFS就A了.. (贴一下丽洁姐的题解: 我们构造S的SAM,那么对于一个节点s,它的长度范围是[Min(s),Max(s)],同时他的出

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 后缀自动机板子

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

[SPOJ8222]NSUBSTR - Substrings 后缀自动机

1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int sz=0,la,rt; 6 int ch[500010][26],l[500010],fa[500010]; 7 void Extend(int c){ 8 int end=++sz,tmp=la; 9 l[end]=l[tmp]+1; 10 while(tmp&&!ch[tm

SPOJ8222 NSUBSTR - Substrings 后缀自动机_动态规划

讲起来不是特别好讲.总之,如果 $dp[i+1]>=dp[i]$,故$dp[i]=max(dp[i],dp[i+1])$ Code: #include <cstdio> #include <algorithm> #include <cstring> #define setIO(s) freopen(s".in","r",stdin) #define maxn 2000000 #define N 30 #define ll l

2019HNCPC C Distinct Substrings 后缀自动机

题意 给定一个长度为n字符串,字符集大小为m(1<=n,m<=1e6),求\(\bigoplus_{c = 1}^{m}\left(h(c) \cdot 3^c \bmod (10^9+7)\right)\)的值.其中h(c)为将c加到字符串末尾产生的新的本质不同的子串数目. 解题思路 比赛的时候没做出来,颁奖的时候听lts和lsx讲了之后发现可以用SAM做,而且板子稍微改改就可以了. 具体就是每次添加一个字符最多新建2个节点,根据SAM的性质,添加c后新建节点对本质不同的子串的数目的贡献就是

【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