循环移位(后缀自动机)

Posted harrypotter-fan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了循环移位(后缀自动机)相关的知识,希望对你有一定的参考价值。

题目描述:

给定一个字符串 s 。现在问你有多少个本质不同的 s 的子串 t=ttt(m>0使得将 t 循环左移一位后变成的 t=ttt1 也是 s 的一个子串。

题解:

技术图片

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=300010;
char s[N];
int n,lst=1,tot=1;
int len[N*2],ch[N*2][26],fa[N*2],pos[N*2];
//pos表示在原串中的位置
int sum[N][26];
ll ans;
void add(int c)
    int p=lst,np=lst=++tot;
    pos[np]=len[np]=len[p]+1;
    for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
    if(!p) fa[np]=1;
    else
        int q=ch[p][c];
        if(len[q]==len[p]+1) fa[np]=q;
        else
            int nq=++tot;
            memcpy(ch[nq],ch[q],sizeof(ch[q]));
            fa[nq]=fa[q];
            len[nq]=len[p]+1;
            pos[nq]=pos[q];
            fa[q]=fa[np]=nq;
            for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
        
    
    return;

int main()
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;i++)
        add(s[i]-a);
    for(int i=1;i<=n;i++)
        for(int j=0;j<26;j++)
            sum[i][j]=sum[i-1][j]+(s[i]-a==j);
    for(int i=2;i<=tot;i++)
        if(ch[fa[i]][s[pos[i]-len[fa[i]]]-a])
            ans++;
        for(int j=0;j<26;j++)
            if(ch[i][j])
                ans+=sum[pos[i]-len[fa[i]]-1][j]-sum[pos[i]-len[i]][j];
    
    printf("%lld",ans);
    return 0;

好了我知道这个不好懂,所以我们再配张图:

技术图片

 

以上是关于循环移位(后缀自动机)的主要内容,如果未能解决你的问题,请参考以下文章

后缀自动机(SAM)解题记录

hihocoder #1465 : 后缀自动机五·重复旋律8

hihocoder 后缀自动机五·重复旋律8 求循环同构串出现的次数

hihocoder #1465 : 后缀自动机五·重复旋律8

后缀自动机

HIHOcoder1465 后缀自动机五·重复旋律8