一、模板:
洛谷P3804

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long
#define llu unsigned ll
using namespace std;
const int maxn=1000100;
char str[maxn];

int x[maxn<<1],y[maxn<<1];
struct Sam
{
    int last,cnt;
    int nt[maxn<<1][26],fa[maxn<<1];
    int len[maxn<<1],sum[maxn<<1];

    void init(void)
    {
        last=1;
        cnt=1;
        fa[1]=0;
        len[1]=0;

    }

    void _insert(int c)
    {
        int nowp=++cnt,p=last;
        len[nowp]=len[last]+1;

        while(p&&!nt[p][c]) nt[p][c]=nowp,p=fa[p];
        if(!p) fa[nowp]=1;
        else
        {
            int q=nt[p][c];
            if(len[q]==len[p]+1) fa[nowp]=q;
            else
            {
                int nowq=++cnt;
                len[nowq]=len[p]+1;
                memcpy(nt[nowq],nt[q],sizeof(nt[q]));

                fa[nowq]=fa[q];
                fa[nowp]=fa[q]=nowq;

                while(p&&nt[p][c]==q) nt[p][c]=nowq,p=fa[p];
            }
        }
        last=nowp;
        sum[last]=1;
        return ;
    }

    void _count(void)
    {
        memset(x,0,sizeof(x));
        for(int i=1;i<=cnt;i++) x[len[i]]++;
        for(int i=1;i<=cnt;i++) x[i]+=x[i-1];
        for(int i=1;i<=cnt;i++) y[x[len[i]]--]=i;
        for(int i=cnt;i>=1;i--)
            sum[fa[y[i]]]+=sum[y[i]];
        return ;

    }

    void creat(void)
    {
        int len=strlen(str);

        init();
        for(int i=0;i<len;i++)
            _insert(str[i]-'a');
        _count();

        return ;
    }
}sam;


int main(void)
{
    scanf("%s",str);
    sam.creat();
    ll maxx=0;
    for(int i=1;i<=sam.cnt;i++)
        if(sam.sum[i]>1)
            maxx=max((ll)sam.sum[i]*sam.len[i],maxx);

    printf("%lld\n",maxx);
    return 0;
}

二、string string string HDU - 6194 :
求出sum数组即可,判断是否与k相等,若相等,则节点i,代表的字符串都符合题意,求出节点i代表的字符串的个数即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long
#define llu unsigned ll
using namespace std;
const int maxn=100100;
char str[maxn];

int x[maxn<<1],y[maxn<<1];
struct Sam
{
    int last,cnt;
    int nt[maxn<<1][26],len[maxn<<1];
    int fa[maxn<<1],sum[maxn<<1];

    void init(int n)
    {
        last=1;
        cnt=1;
        fa[1]=0;
        len[1]=0;

        for(int i=0;i<=n;i++)
        {
            fa[i]=0;
            len[i]=0;
            sum[i]=0;
            memset(nt[i],0,sizeof(nt[i]));
        }
    }

    void _insert(int c)
    {
        int nowp=++cnt,p=last;
        len[nowp]=len[last]+1;

        while(p&&!nt[p][c]) nt[p][c]=nowp,p=fa[p];

        if(!p) fa[nowp]=1;
        else
        {
            int q=nt[p][c];
            if(len[q]==len[p]+1) fa[nowp]=q;
            else
            {
                int nowq=++cnt;
                len[nowq]=len[p]+1;
                memcpy(nt[nowq],nt[q],sizeof(nt[q]));

                fa[nowq]=fa[q];
                fa[nowp]=fa[q]=nowq;

                while(p&&nt[p][c]==q) nt[p][c]=nowq,p=fa[p];
            }
        }
        last=nowp,sum[last]=1;
        return ;
    }

    void _count(void)
    {
        memset(x,0,sizeof(x));
        for(int i=1;i<=cnt;i++) x[len[i]]++;
        for(int i=1;i<=cnt;i++) x[i]+=x[i-1];
        for(int i=1;i<=cnt;i++) y[x[len[i]]--]=i;
        for(int i=cnt;i>=1;i--) sum[fa[y[i]]]+=sum[y[i]];
        return ;
    }

    void creat(void)
    {
        int len=strlen(str);

        init((len+5)*2);
        for(int i=0;i<len;i++)
            _insert(str[i]-'a');
        _count();

        return ;
    }
}sam;

int main(void)
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int k;
        scanf("%d%s",&k,str);
        sam.creat();
        ll ans=0;
        for(int i=1;i<=sam.cnt;i++)
        {
            if(sam.sum[i]==k)
            {
                ans+=(sam.len[i]-sam.len[sam.fa[i]]);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

三、后缀数组一·重复旋律 HihoCoder - 1403:
至少出现k次的可重叠最长子串:
求出sum数组,sum≥k时,用len【i】更新最大值即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long
#define llu unsigned ll
using namespace std;
const int maxn=20100;
char str[maxn];

int x[maxn<<1],y[maxn<<1];
struct Sam
{
    int last,cnt;
    int nt[maxn<<1][101],len[maxn<<1];
    int fa[maxn<<1],sum[maxn<<1];

    void init(int n)
    {
        last=1;
        cnt=1;
        fa[1]=0;
        len[1]=0;

        for(int i=0;i<=n;i++)
        {
            fa[i]=0;
            len[i]=0;
            sum[i]=0;
            memset(nt[i],0,sizeof(nt[i]));
        }
    }

    void _insert(int c)
    {
        int nowp=++cnt,p=last;
        len[nowp]=len[last]+1;

        while(p&&!nt[p][c]) nt[p][c]=nowp,p=fa[p];

        if(!p) fa[nowp]=1;
        else
        {
            int q=nt[p][c];
            if(len[q]==len[p]+1) fa[nowp]=q;
            else
            {
                int nowq=++cnt;
                len[nowq]=len[p]+1;
                memcpy(nt[nowq],nt[q],sizeof(nt[q]));

                fa[nowq]=fa[q];
                fa[nowp]=fa[q]=nowq;

                while(p&&nt[p][c]==q) nt[p][c]=nowq,p=fa[p];
            }
        }
        last=nowp,sum[last]=1;
        return ;
    }

    void _count(void)
    {
        memset(x,0,sizeof(x));
        for(int i=1;i<=cnt;i++) x[len[i]]++;
        for(int i=1;i<=cnt;i++) x[i]+=x[i-1];
        for(int i=1;i<=cnt;i++) y[x[len[i]]--]=i;
        for(int i=cnt;i>=1;i--) sum[fa[y[i]]]+=sum[y[i]];
        return ;
    }

    void creat(int n)
    {

        init((n+5)*2);
        int t;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&t);
            _insert(t);
        }
        _count();

        return ;
    }
}sam;

int main(void)
{
    int n,k;
    scanf("%d%d",&n,&k);
    sam.creat(n);
    int maxx=0;
    for(int i=1;i<=sam.cnt;i++)
        if(sam.sum[i]>=k) maxx=max(maxx,sam.len[i]);

    printf("%d\n",maxx);
    return 0;
}

四、两个串的最长公共子串,已用后缀数组解决过,现在用后缀自动机解决:
parents树上fa(i)是i的后缀
直接跑nt即可:
Longest Common Substring SPOJ - LCS:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long
#define llu unsigned ll
using namespace std;
const int maxn=250100;
char str[maxn];
char str1[maxn];

int x[maxn<<1],y[maxn<<1];
struct Sam
{
    int last,cnt;
    int nt[maxn<<1][26],len[maxn<<1];
    int fa[maxn<<1],sum[maxn<<1];

    void init(int n)
    {
        last=1;
        cnt=1;
        fa[1]=0;
        len[1]=0;

        for(int i=0;i<=n;i++)
        {
            fa[i]=0;
            len[i]=0;
            sum[i]=0;
            memset(nt[i],0,sizeof(nt[i]));
        }
    }

    void _insert(int c)
    {
        int nowp=++cnt,p=last;
        len[nowp]=len[last]+1;

        while(p&&!nt[p][c]) nt[p][c]=nowp,p=fa[p];

        if(!p) fa[nowp]=1;
        else
        {
            int q=nt[p][c];
            if(len[q]==len[p]+1) fa[nowp]=q;
            else
            {
                int nowq=++cnt;
                len[nowq]=len[p]+1;
                memcpy(nt[nowq],nt[q],sizeof(nt[q]));

                fa[nowq]=fa[q];
                fa[nowp]=fa[q]=nowq;

                while(p&&nt[p][c]==q) nt[p][c]=nowq,p=fa[p];
            }
        }
        last=nowp,sum[last]=1;
        return ;
    }

    void _count(void)
    {
        memset(x,0,sizeof(x));
        for(int i=1;i<=cnt;i++) x[len[i]]++;
        for(int i=1;i<=cnt;i++) x[i]+=x[i-1];
        for(int i=1;i<=cnt;i++) y[x[len[i]]--]=i;
        for(int i=cnt;i>=1;i--) sum[fa[y[i]]]+=sum[y[i]];
        return ;
    }

    void creat(void)
    {

        int len=strlen(str);
        init((len+5)*2);
        int t;
        for(int i=0;i<len;i++)
            _insert(str[i]-'a');

        //_count();

        return ;
    }
    int fi(void)
    {
        int lenn=strlen(str1);
        int ans=0;
        int res=0;
        int now=1;
        for(int i=0;i<lenn;i++)
        {
            if(nt[now][str1[i]-'a']) res++,now=nt[now][str1[i]-'a'];
            else
            {
                while(now&&!nt[now][str1[i]-'a']) now=fa[now];
                if(!now) res=0,now=1;
                else res=len[now]+1,now=nt[now][str1[i]-'a'];
            }
            ans=max(ans,res);
        }
        return ans;
    }
}sam;

int main(void)
{
    while(scanf("%s%s",str,str1)!=EOF)
    {
        sam.creat();
        printf("%d\n",sam.fi());
    }

    return 0;
}

五、 Longest Common Substring II
多个串的最长公共子串:对其中一个串建立后缀自动机,其他串分别与这个串匹配,取每个匹配位置 i 的最小值。
对最终答案所有 i 取最大值。
在更新 i 的过程中,有可能子节点已更新但是父节点没有更新,实际上父节点dp应该是有值的,我们按照拓扑序更新一下父节点即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long
#define llu unsigned ll
using namespace std;
const int maxn=120100;
char str[maxn];
char str1[maxn];
int dp[maxn<<1];
int ans[maxn<<1];

int x[maxn<<1],y[maxn<<1];
struct Sam
{
    int last,cnt;
    int nt[maxn<<1][26],len[maxn<<1];
    int fa[maxn<<1],sum[maxn<<1];

    void init(int n)
    {
        last=1;
        cnt=1;
        fa[1]=0;
        len[1]=0;

        for(int i=0;i<=n;i++)
        {
            fa[i]=0;
            len[i]=0;
            sum[i]=0;
            memset(nt[i],0,sizeof(nt[i]));
        }
    }

    void _insert(int c)
    {
        int nowp=++cnt,p=last;
        len[nowp]=len[last]+1;

        while(p&&!nt[p][c]) nt[p][c]=nowp,p=fa[p];

        if(!p) fa[nowp]=1;
        else
        {
            int q=nt[p][c];
            if(len[q]==len[p]+1) fa[nowp]=q;
            else
            {
                int nowq=++cnt;
                len[nowq]=len[p]+1;
                memcpy(nt[nowq],nt[q],sizeof(nt[q]));

                fa[nowq]=fa[q];
                fa[nowp]=fa[q]=nowq;

                while(p&&nt[p][c]==q) nt[p][c]=nowq,p=fa[p];
            }
        }
        last=nowp,sum[last]=1;
        return ;
    }

    void _count(void)
    {
        memset(x,0,sizeof(x));
        for(int i=1;i<=cnt;i++) x[len[i]]++;
        for(int i=1;i<=cnt;i++) x[i]+=x[i-1];
        for(int i=1;i<=cnt;i++) y[x[len[i]]--]=i;
        for(int i=cnt;i>=1;i--) sum[fa[y[i]]]+=sum[y[i]];
        return ;
    }

    void creat(void)
    {

        int len=strlen(str);
        init((len+5)*2);
        int t;
        for(int i=0;i<len;i++)
            _insert(str[i]-'a');

        _count();

        return ;
    }
    void fi(void)
    {
        memset(dp,0,sizeof(dp));
        int lenn=strlen(str1);
        int res=0;
        int now=1;
        for(int i=0;i<lenn;i++)
        {
            if(nt[now][str1[i]-'a']) res++,now=nt[now][str1[i]-'a'];
            else
            {
                while(now&&!nt[now][str1[i]-'a']) now=fa[now];
                if(!now) res=0,now=1;
                else res=len[now]+1,now=nt[now][str1[i]-'a'];
            }
            dp[now]=max(dp[now],res);
        }

        for(int i=cnt;i>=1;i--)
            dp[fa[y[i]]]=max(dp[fa[y[i]]],min(dp[y[i]],len[fa[y[i]]]));
        for(int i=1;i<=cnt;i++)
            ans[i]=min(ans[i],dp[i]);
        return ;
    }
}sam;

int main(void)
{
    scanf("%s",str);
    sam.creat();
    for(int i=1;i<=sam.cnt;i++)
        ans[i]=sam.len[i];
    while(scanf("%s",str1)!=EOF)
    {
        sam.fi();
    }
    int maxx=0;
    for(int i=1;i<=sam.cnt;i++)
        maxx=max(maxx,ans[i]);

    printf("%d\n",maxx);


    return 0;
}

六、长度为 i 的串出现的最多的出现次数:
对于每个出现次数 i,维护这个节点出现所有子串长度的最大值即可:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long
#define llu unsigned ll
using namespace std;
const int maxn=250100;
char str[maxn];
char str1[maxn];


int x[maxn<<1],y[maxn<<1];
struct Sam
{
    int last,cnt;
    int nt[maxn<<1][26],len[maxn<<1];
    int fa[maxn<<1],sum[maxn<<1];

    void init(int n)
    {
        last=1;
        cnt=1;
        fa[1]=0;
        len[1]=0;

        for(int i=0;i<=n;i++)
        {
            fa[i]=0;
            len[i]=0;
            sum[i]=0;
            memset(nt[i],0,sizeof(nt[i]));
        }
    }

    void _insert(int c)
    {
        int nowp=++cnt,p=last;
        len[nowp]=len[last]+1;

        while(p&&!nt[p][c]) nt[p][c]=nowp,p=fa[p];

        if(!p) fa[nowp]=1;
        else
        {
            int q=nt[p][c];
            if(len[q]==len[p]+1) fa[nowp]=q;
            else
            {
                int nowq=++cnt;
                len[nowq]=len[p]+1;
                memcpy(nt[nowq],nt[q],sizeof(nt[q]));

                fa[nowq]=fa[q];
                fa[nowp]=fa[q]=nowq;

                while(p&&nt[p][c]==q) nt[p][c]=nowq,p=fa[p];
            }
        }
        last=nowp,sum[last]=1;
        return ;
    }

    void _count(void)
    {
        memset(x,0,sizeof(x));
        for(int i=1;i<=cnt;i++) x[len[i]]++;
        for(int i=1;i<=cnt;i++) x[i]+=x[i-1];
        for(int i=1;i<=cnt;i++) y[x[len[i]]--]=i;
        for(int i=cnt;i>=1;i--) sum[fa[y[i]]]+=sum[y[i]];
        return ;
    }

    void creat(void)
    {

        int len=strlen(str);
        init((len+5)*2);
        int t;
        for(int i=0;i<len;i++)
            _insert(str[i]-'a');

        _count();

        return ;
    }

}sam;

struct node
{
    int maxx;
    int l,r;
    int laz=0;
}tree[maxn<<2];

void bulid(int l,int r,int cnt)
{
    tree[cnt].l=l,tree[cnt].r=r;
    if(l==r)
    {
        tree[cnt].maxx=0;
        tree[cnt].laz=0;
        return ;
    }

    int mid=(l+r)>>1;
    bulid(l,mid,cnt<<1);
    bulid(mid+1,r,cnt<<1|1);
    tree[cnt].maxx=max(tree[cnt<<1].maxx,tree[cnt<<1|1].maxx);
    return ;
}

void pushdown(int cnt)
{
    if(tree[cnt].laz)
    {
        tree[cnt<<1].laz=max(tree[cnt].laz,tree[cnt<<1].laz);
        tree[cnt<<1|1].laz=max(tree[cnt].laz,tree[cnt<<1|1].laz);
        tree[cnt<<1].maxx=max(tree[cnt].laz,tree[cnt<<1].maxx);
        tree[cnt<<1|1].maxx=max(tree[cnt].laz,tree[cnt<<1|1].maxx);
        tree[cnt].laz=0;
    }
    return ;
}

void change(int l,int r,int val,int cnt)
{
    if(l<=tree[cnt].l&&tree[cnt].r<=r)
    {
        tree[cnt].maxx=max(tree[cnt].maxx,val);
        tree[cnt].laz=max(tree[cnt].laz,val);
        return ;
    }
    pushdown(cnt);
    if(l<=tree[cnt<<1].r) change(l,r,val,cnt<<1);
    if(r>=tree[cnt<<1|1].l) change(l,r,val,cnt<<1|1);

    tree[cnt].maxx=max(tree[cnt<<1].maxx,tree[cnt<<1|1].maxx);
}


int ask(int pos,int cnt)
{
    if(tree[cnt].l==tree[cnt].r)
    {
        return tree[cnt].maxx;
    }
    pushdown(cnt);
    if(pos<=tree[cnt<<1].r) return ask(pos,cnt<<1);
    else return ask(pos,cnt<<1|1);
}


int main(void)
{
    while(scanf("%s",str)!=EOF)
    {
        sam.creat();
        int lenn=strlen(str);
        bulid(1,lenn,1);
        for(int i=1;i<=sam.cnt;i++)
        {
            int l=sam.len[sam.fa[i]]+1;
            int r=sam.len[i];
            if(l>r) continue;
            //cout<<sam.len[sam.fa[i]]+1<<" "<<sam.len[i]<<" "<<sam.sum[i]<<endl;
            change(l,r,sam.sum[i],1);
        }

        for(int i=1;i<=lenn;i++)
        {
            printf("%d\n",ask(i,1));
        }
    }
    return 0;


    return 0;
}

七、找字典序第k小子串,其中子串不重复:
处理trie树,跑出所有子串,然后找就可以了:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long
#define llu unsigned ll
using namespace std;
const int maxn=90100;
char str[maxn];
char str1[maxn];


int x[maxn<<1],y[maxn<<1];
struct Sam
{
    int last,cnt;
    int nt[maxn<<1][26],len[maxn<<1];
    int fa[maxn<<1],sum[maxn<<1];
    int ans[maxn<<1];

    void init(int n)
    {
        last=1;
        cnt=1;
        fa[1]=0;
        len[1]=0;

        for(int i=0;i<=n;i++)
        {
            fa[i]=0;
            len[i]=0;
            sum[i]=0;
            ans[i]=0;
            memset(nt[i],0,sizeof(nt[i]));
        }
    }

    void _insert(int c)
    {
        int nowp=++cnt,p=last;
        len[nowp]=len[last]+1;

        while(p&&!nt[p][c]) nt[p][c]=nowp,p=fa[p];

        if(!p) fa[nowp]=1;
        else
        {
            int q=nt[p][c];
            if(len[q]==len[p]+1) fa[nowp]=q;
            else
            {
                int nowq=++cnt;
                len[nowq]=len[p]+1;
                memcpy(nt[nowq],nt[q],sizeof(nt[q]));

                fa[nowq]=fa[q];
                fa[nowp]=fa[q]=nowq;

                while(p&&nt[p][c]==q) nt[p][c]=nowq,p=fa[p];
            }
        }
        last=nowp,sum[last]=1;
        return ;
    }

    void _count(void)
    {
        memset(x,0,sizeof(x));
        for(int i=1;i<=cnt;i++) x[len[i]]++;
        for(int i=1;i<=cnt;i++) x[i]+=x[i-1];
        for(int i=1;i<=cnt;i++) y[x[len[i]]--]=i;
        for(int i=cnt;i>=1;i--) sum[fa[y[i]]]+=sum[y[i]];
        for(int i=cnt;i>=1;i--)
        {
            ans[y[i]]=1;
            for(int j=0;j<26;j++)
                ans[y[i]]+=ans[nt[y[i]][j]];
        }
        return ;
    }

    void creat(void)
    {

        int len=strlen(str);
        init((len+5)*2);
        int t;
        for(int i=0;i<len;i++)
            _insert(str[i]-'a');

        _count();

        return ;
    }

}sam;



int main(void)
{
    while(scanf("%s",str)!=EOF)
    {
        sam.creat();
        int t,kk;
        scanf("%d",&t);
        for(int i=1;i<=t;i++)
        {
            scanf("%d",&kk);
            int pp=1;
            while(kk)
            {
                for(int j=0;j<26;j++)
                {
                    if(sam.nt[pp][j])
                    {
                        if(sam.ans[sam.nt[pp][j]]>=kk)
                        {
                            putchar(j+'a');
                            pp=sam.nt[pp][j];
                            kk--;
                            break;
                        }
                        else kk-=sam.ans[sam.nt[pp][j]];
                    }
                }
            }

            putchar('\n');
        }

    }

    return 0;
}