hihocoder1445 后缀自动机二·重复旋律5

传送门:http://hihocoder.com/problemset/problem/1445

【题解】

大概看了一天的后缀自动机,总算懂了一些

这篇文章写的非常好,诚意安利:Suffix Automaton Tutorial - Hunt Zhan

我就是看了这个大概懂了。

整个过程大概是:每次插入一个state可能会分裂原有的state的transition,就维护这个transition即可。

要用par[x]记录suffix-link是谁。

过程中可以不用记录minlen,因为$minlen[i] = maxlen[par[i]] + 1$,这点非常重要。

这题前面写了后缀自动机,然后上面像统计子树一样统计,后来发现,复杂度是$O(n * 26)$,似乎太大了,TLE了。

其实后缀自动机的每个state都含有若干子串,所有state的含有子串个数之和就是总个数了。

每个state含有子串个数为$maxlen[i] - minlen[i]$,这里把$minlen[i]$替换成$maxlen[par[i]] + 1$即可,不需要再求$minlen[i]$。

这样复杂度就差不多$O(n)$了,常数小了。

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N = 1e6 + 10, M = 2e6 + 3;
const int mod = 1e9+7;

char str[N];
struct SAM {
    int ch[M][26], par[M], ml[M];
    int siz, rt, last;
    inline void set() {
        siz = rt = last = 1;
        memset(ch, 0, sizeof ch);
        memset(par, 0, sizeof par);
        memset(ml, 0, sizeof ml);
    }
    inline void extend(int c) {
        int p = last, cur = ++siz;
        ml[cur] = ml[p] + 1;
        for (; p && !ch[p][c]; p = par[p]) ch[p][c] = cur;
        if(!p) par[cur] = rt;
        else {
            int q = ch[p][c];
            if(ml[q] == ml[p] + 1) par[cur] = q;
            else {
                int sq = ++siz;
                par[sq] = par[q];
                for (int i=0; i<26; ++i) ch[sq][i] = ch[q][i];
                ml[sq] = ml[p] + 1;
                par[q] = par[cur] = sq;
                for (; p && ch[p][c] == q; p = par[p]) ch[p][c] = sq;
            }
        }
        last = cur;
    }
}S;

/*
ll f[M];
inline void dfs(int x) {
    f[x] = 1;
    for (int i=0; i<26; ++i) {
        if(!S.ch[x][i]) continue;
        dfs(S.ch[x][i]);
        f[x] += f[S.ch[x][i]];
    }
}
*/

int main() {
    scanf("%s", str+1); S.set();
    for (int i=1; str[i]; ++i) S.extend(str[i] - ‘a‘);
    ll ans = 0;
    for (int i=1; i<=S.siz; ++i) {
        if(i == S.rt) continue;
        ans += S.ml[i] - S.ml[S.par[i]];
    }
    cout << ans;
    return 0;
}

时间: 2024-10-08 10:28:56

hihocoder1445 后缀自动机二·重复旋律5的相关文章

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

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

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

后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数.但是K不是固定的,小Hi想知道对于所有的K的答案. 解题方法提示 输入 共一行,包含一个由小写字母构成的字符串S.字符串长度不超过 1000000. 输出 共Length(S)行,每行一个整数,表示答案. 样例输入 aab 样例输出

hihocoder 后缀自动机二&#183;重复旋律5

求不同子串个数 裸的后缀自动机 1 #include<cstring> 2 #include<cmath> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdio> 6 7 #define ll long long 8 #define N 2000007 9 using namespace std; 10 inline int read() 11 { 12 int x=0,f=1;

HIHOcoder 1445 后缀自动机二&#183;重复旋律5

思路 题目要求求出有多少个不同的子串出现 因为后缀自动机每个状态存储的是连续的后缀,所以一个状态对应的子串个数就是maxlen[x]-minlen[x]+1 代码 #include <cstdio> #include <algorithm> #include <cstring> #include <iostream> using namespace std; const int MAXN = 1000100*2; int maxlen[MAXN],minle

hihocoder #1465 : 后缀自动机五&#183;重复旋律8

#1465 : 后缀自动机五·重复旋律8 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 小Hi发现旋律可以循环,每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以对“循环相似旋律”进行相同的变换能继续得到原串的“循环相似旋律”. 小Hi对此产生了浓厚的兴趣,他有若干段旋律,和一部音乐作品.对于每一段旋律,他想知道有多少在音乐作品中的子串(重复便多

hihocoder #1407 : 后缀数组二&#183;重复旋律2

#1407 : 后缀数组二·重复旋律2 Time Limit:5000ms Case Time Limit:1000ms Memory Limit:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列.小Hi在练习过很多曲子以后发现很多作品自身包含一样的旋律. 旋律可以表示为一段连续的数列,相似的旋律在原数列不可重叠,比如在1 2 3 2 3 2 1 中 2 3 2 出现了一次,2 3 出现了两次,小Hi想知道一段旋律中出现次数至少为两次

hihocoder #1449 : 后缀自动机三&#183;重复旋律6

#1449 : 后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数.但是K不是固定的,小Hi想知道对于所有的K的答案. 解题方法提示 × 解题方法提示 小Hi:上次我们已经学习了后缀自动机了,今天我们再来解决一个用到后缀自动机的问题. 小Ho:好!那我们开始吧! 小Hi:现在我们要对K

hihocoder #1457 : 后缀自动机四&#183;重复旋律7

#1457 : 后缀自动机四·重复旋律7 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的是小Hi发现了一部名字叫<十进制进行曲大全>的作品集,顾名思义,这部作品集里有许多作品,但是所有的作品有一个共同特征:只用了十个音符,所有的音符都表示成0-9的数字. 现在小Hi想知道这部作品中所有不同的旋律的“和”(也就是把串看成数字,在十进制下的求和,允许有前导0).答案有可能

BZOJ 后缀自动机四&#183;重复旋律7

后缀自动机四·重复旋律7 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的是小Hi发现了一部名字叫<十进制进行曲大全>的作品集,顾名思义,这部作品集里有许多作品,但是所有的作品有一个共同特征:只用了十个音符,所有的音符都表示成0-9的数字. 现在小Hi想知道这部作品中所有不同的旋律的“和”(也就是把串看成数字,在十进制下的求和,允许有前导0).答案有可能很大,我们需要对