后缀自动机模板——不同子串个数p2408

后缀自动机的入门博客 https://www.luogu.org/blog/Kesdiael3/hou-zhui-zi-dong-ji-yang-xie

有两种求法,分别对应了两种性质

#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
char s[maxn];
int n;

int cmp(int a,int b);
struct SAM{
    int cnt,last;
    int nxt[maxn][26];
    int link[maxn];
    int len[maxn];
    long long ans[maxn];
    SAM(){
        cnt=last=1;
    }
    void insert(int c){
        int p=last,np=last=++cnt;
        len[np]=len[p]+1;
        for(;p&&!nxt[p][c];p=link[p])
            nxt[p][c]=np;
        if(!p) {link[np]=1;return;}

        int q=nxt[p][c];
        if(len[q]==len[p]+1){link[np]=q;return;}

        int clone=++cnt;
        link[clone]=link[q];
        len[clone]=len[p]+1;
        memcpy(nxt[clone],nxt[q],sizeof nxt[q]);
        link[q]=link[np]=clone;
        for(;p&&nxt[p][c]==q;p=link[p])
            nxt[p][c]=clone;
    }
    int id[maxn<<1];
    void calc(){
        for(int i=1;i<=cnt;i++)id[i]=i;
        sort(id+1,id+cnt+1,cmp);//按状态所对应的长度排序
        for(int i=1;i<=cnt;i++)
            for(int j=0;j<26;j++)
                if(nxt[id[i]][j])
                    ans[id[i]]+=ans[nxt[id[i]][j]]+1;
    }
    void calc2(){//这里两种写法都可以
        for(int i=1;i<=cnt;i++)
            ans[1]+=len[i]-len[link[i]];
    }
}p;
int cmp(int a,int b){return p.len[a]>p.len[b];}

int main(){
    scanf("%d%s",&n,s);
    for(int i=0;i<n;i++)
        p.insert(s[i]-‘a‘);
    p.calc();
    cout<<p.ans[1]<<endl;
}

原文地址:https://www.cnblogs.com/zsben991126/p/11309136.html

时间: 2024-08-05 10:18:07

后缀自动机模板——不同子串个数p2408的相关文章

hdu4622(后缀自动机模板)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意: 先输入一个长度为 n 的字符串, 然后有 q 个形如 l, r 的询问, 对于每个询问输出区间 [l, r] 中有多少不同的子串 思路: 后缀自动机模板 代码: 1 // 后缀自动机要理解其含义,从起点到每个点的不同路径,就是不同的子串. 2 // 到每一个点,不同路径,其实就是以这个点为最后一个字符的后缀,长度是介于(p->fa->len,p->len]之间的,个数也就清楚

不在B中的A的子串数量 HDU - 4416 (后缀自动机模板题目)

题目: 给定一个字符串a,又给定一系列b字符串,求字符串a的子串不在b中出现的个数. 题解: 先将所有的查询串放入后缀自动机(每次将sam.last=1)(算出所有子串个数) 然后将母串放入后缀自动机然后记录这个子串个数 两个值相减即可 1 #include <set> 2 #include <map> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <

SETI ACdream - 1430 后缀自动机求不相交子串

http://blog.csdn.net/gatevin/article/details/45875343 题目是求不重叠的不同子串个数 一般来说,endpos集合包含了子串结尾位置,每个状态都包含了若干子串.endpos集合的大小就是这些子串的出现次数 但是这样会重叠.那么可以求出endpos结合的结尾最小值,和结尾最大值. 那么长度小于mx - mi的子串,是肯定不会重叠的 至于有多少个,可以由mxcnt决定 #include <bits/stdc++.h> #define IOS ios

[spoj DISUBSTR]后缀数组统计不同子串个数

题目链接:https://vjudge.net/contest/70655#problem/C 后缀数组的又一神奇应用.不同子串的个数,实际上就是所有后缀的不同前缀的个数. 考虑所有的后缀按照rank排好了,我们现在已知height,也就是相邻的两个的最长公共前缀是多少.那么不同的子串个数怎么统计呢? 从第一个串开始考虑,ans+=L1.再看第二个串,会加进来几个不同的前缀呢?就是ans+=L2-height[2].第三个类似,会加进来ans+=L3-height[3]-- 因此最后的结果就是a

POJ 1509 Glass Beads 后缀自动机 模板 字符串的最小表示

http://poj.org/problem?id=1509 后缀自动机其实就是一个压缩储存空间时间(对节点重复利用)的储存所有一个字符串所有子串的trie树,如果想不起来长什么样子可以百度一下找个图回忆,从0开始到任意一个点的串都是字符串的子串. 有一些很好用的性质. 字符串的最小表示就是把一个字符串首尾相连再从任意一个地方断开产生的字典序最小的字符串,这个题是求最小表示的开头字母在原字符串中的下标(从1开始). 具体看实现吧,没什么可以解释的地方. 1 #include<iostream>

广义后缀自动机模板

后缀自动机能解决很多单串的问题.但是一旦到了多串的情况.可能就会变得有些棘手 这个时候你可能会想能不能将多个串一起构建出和单串后缀自动机那样子拥有诸多优美性质的自动机呢? 答案当然是有的.那就是广义后缀自动机 对于广义后缀自动机.和普通的后缀自动机写法上有些许不同之处 大致就是在插入新串的时候.需要把当前状态指针 last 指回 root 还有一个问题.网上的人们都说广义后缀自动机在新插入节点的时候要判是否已经存在 这个就造成了代码的迥异 关于代码.借鉴了这个博客 ==> Click here

后缀自动机模板(初步)

看了几天居然连后缀自动机的构造原理和性质都没完全搞懂...更不用说应用了. 在这里膜一下先辈CLJ大神(的PPt),大神的世界就是不懂.另外还要膜一下国家集训队的几篇论文作者,表示还没看懂orz 先贴一个讲得通俗易懂的后缀自动机学习网站(蒟蒻的我居然仍然没看懂),讲得也够详细.学习网站 苦逼的我·一个下午就死记硬背了这篇代码.感觉:看代码比看论文里的长篇大论简单多了(我是蒟蒻). 代码贴上(终于背下来了): 1 #include<cstdio> 2 #include<string.h&g

【模板】广义后缀自动机模板

建立在tire上的后缀自动机,采用bfs的建图方式,可以保证复杂度 #include<bits/stdc++.h> using namespace std; #define fu(a,b,c) for(int a=b;a<=c;++a) #define fd(a,b,c) for(int a=b;a>=c;--a) #define MAXN 2000010 #define LL long long const int CHARSET_SIZE=10; //Suffix_Automa

SPOJ Distinct Substrings(后缀数组求不同子串个数,好题)

DISUBSTR - Distinct Substrings no tags Given a string, we need to find the total number of its distinct substrings. Input T- number of test cases. T<=20; Each test case consists of one string, whose length is <= 1000 Output For each test case output