P3804 后缀自动机模版

题意

给定一个只包含小写字母的字符串 S,

请你求出 S 的所有出现次数不为 1 的子串的出现次数乘上该子串长度的最大值。

传送门

思路

后缀自动机,parent树上dfs。

code

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e6+10;
const int maxm = maxn<<1;

long long ans = 0;

struct SAM {
    int len[maxm], link[maxm], cnt[maxm];
    int a[maxm], c[maxm];
    int nxt[maxm][26];
    int last, tot;

    int head[maxm], v[maxm], nt[maxm], num;
    void addEdge(int u, int _v) {
        v[num] = _v, nt[num] = head[u];
        head[u] = num++;
    }
//    vector<int> g[maxn<<1];

    void init() {
        len[0] = link[0] = 0;
        last = tot = 1;
    }

    void extend(int c) {
        c -= 'a';
        int cur = ++tot, p = last;
        len[cur] = len[last] + 1;
        cnt[cur] = 1;
        for (; p && !nxt[p][c]; p = link[p]) nxt[p][c] = cur;
        if(!p) {
            link[cur] = 1;
        } else {
            int q = nxt[p][c];
            if(len[q] == len[p]+1) {
                link[cur] = q;
            } else {
                int clone = ++tot;
                len[clone] = len[p] + 1;
                memcpy(nxt[clone], nxt[q], sizeof(nxt[q]));
                link[clone] = link[q];
                for (; p!=-1 && nxt[p][c]==q; p=link[p]) nxt[p][c] = clone;
                link[q] = link[cur] = clone;
            }
        }
        last = cur;
    }

    void build() {
        for (int i = 1; i <= tot; ++i) head[i] = -1; num = 0;
        for (int i = 2; i <= tot; ++i)
            addEdge(link[i], i);
    }

    void dfs(int x) {    // parent树上dfs, vector T了, 前向星2.98s, mx = 494ms
        for (int i = head[x]; ~i; i=nt[i]) {
            dfs(v[i]);
            cnt[x] += cnt[v[i]];
        }
        if(cnt[x] > 1) ans = max(ans, 1ll*cnt[x]*len[x]);
    }

    void count() { // 利用基数排序模拟dfs过程 , 3.65s, mx = 982ms
        long long ans = 0;
        for (int i = 1; i <= tot; ++i) ++c[len[i]];
        for (int i = 1; i <= tot; ++i) c[i] += c[i-1];
        for (int i = 1; i <= tot; ++i) a[c[len[i]]--] = i;
        for (int i = tot; i; --i) {
            int p = a[i];
            cnt[link[p]] += cnt[p];
            if(cnt[p]>1) ans = max(ans, 1ll*cnt[p]*len[p]);
        }
        printf("%lld\n", ans);
    }
}sam;
char str[maxn];

int main() {
    sam.init();
    scanf("%s", str);
    for (int i = 0; str[i]; ++i) sam.extend(str[i]);
    sam.build();
    sam.dfs(1);
    printf("%lld\n", ans);
//    sam.count();
    return 0;
}

原文地址:https://www.cnblogs.com/acerkoo/p/11619372.html

时间: 2024-08-30 12:58:46

P3804 后缀自动机模版的相关文章

洛谷 P3804 后缀自动机

题目描述 给定一个只包含小写字母的字符串SS , 请你求出 SS 的所有出现次数不为 11 的子串的出现次数乘上该子串长度的最大值. 输入输出格式 输入格式: 一行一个仅包含小写字母的字符串SS 输出格式: 一个整数,为 所求答案 输入输出样例 输入样例#1: abab 输出样例#1: 4 说明 对于10\%10% 的数据,|S|<=1000∣S∣<=1000 对于100\%100% 的数据,|S|<=10^6∣S∣<=106 今天上午恶补了一下后缀自动机,发现好像没有想象中的那么

后缀自动机 模版

#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=2000100; const int INF=1e9+10; struct SAM { int ch[maxn][26]; int pre[maxn],step[maxn]

洛谷P3804 - 【模板】后缀自动机

Portal Description 模板题啦~ 推荐WJMZBMR在WC2012上的讲义<后缀自动机>. Code //[模板]后缀自动机 #include <cstdio> int max(int x,int y) {return x>y?x:y;} int const N=2e6+10; int n; char s[N]; int rt,ndCnt,last; int fa[N],ch[N][26],len[N],siz[N]; void ins(int x) { in

P3804 【模板】后缀自动机

\(\color{#0066ff}{ 题目描述 }\) 给定一个只包含小写字母的字符串\(S\), 请你求出 \(S\) 的所有出现次数不为 \(1\) 的子串的出现次数乘上该子串长度的最大值. \(\color{#0066ff}{输入格式}\) 一行一个仅包含小写字母的字符串\(S\) \(\color{#0066ff}{输出格式}\) 一个整数,为 所求答案 \(\color{#0066ff}{输入样例}\) abab \(\color{#0066ff}{输出样例}\) 4 \(\color

后缀自动机(SAM) 合集

先上模板 int len[maxn << 1],fa[maxn << 1],son[maxn << 1][maxc]; LL num[maxn << 1]; int size,last; void Init(){ size = last = 1; } void insert(char c){ int s = c - 'a'; int p = last,np = ++size;last = np; num[np] = 1; //主链结点出现次数 + 1 len

『后缀自动机入门 SuffixAutomaton』

本文的图片材料多数来自\(\mathrm{hihocoder}\)中详尽的\(SAM\)介绍,文字总结为原创内容. 确定性有限状态自动机 DFA 首先我们要定义确定性有限状态自动机\(\mathrm{DFA}\),一个有限状态自动机可以用一个五元组\((\mathrm{S},\Sigma,\mathrm{st},\mathrm{end},\delta)\)表示,他们的含义如下: \(1.\) \(\mathrm{S}\) 代表自动机的状态集 \(2.\) \(\Sigma\) 代表字符集,也称字

hiho一下第128周 后缀自动机二&#183;重复旋律5

#1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中出现了多少不同的旋律? 解题方法提示 输入 共一行,包含一个由小写字母构成的字符串.字符串长度不超过 1000000. 输出 一行一个整数,表示答案. 样例输入 aab 样例输出 5 解题方法提示 小Hi:本周的题目其实就是给定一个字符串S,要求出S的所有不同子串的数

后缀自动机总结

后缀自动机是一种确定性有限自动机(DFA),它可以且仅可以匹配一个给定串的任意后缀. 构造一个可以接受一个给定串的所有后缀的不确定性有限自动机(NFA)是很容易的,我们发现我们用通用的将NFA转换成对应DFA的算法转换出来的DFA的状态数都很小(O(n)级别的,远远达不到指数级别).于是,人们就开始研究这种特殊的NFA,并提出了在线增量算法,用O(n)的时间复杂度构造该NFA的DFA.在转换过程中,DFA中对应的NFA中的状态集合其实就是我们的right集合.——————以上在胡扯———————

BZOJ 2946 Poi2000 公共串 后缀自动机

题目大意:求n个串的最长公共子串 太久没写SAM了真是-- 将第一个串建成后缀自动机,用其它的串进去匹配 每个节点记录每个串在上面匹配的最大长度 那么这个节点对答案的贡献就是所有最大长度的最小值 对所有贡献取最大就行了= = 这最大最小看着真是别扭 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 10100 using namesp