【未知来源】循环移位

题意

  给定一个字符串 \(s\),问有多少个本质不同的 \(s\) 的子串 \(t=t_1 t_2 \cdots t_m\space (m\gt 0)\) 使得将 \(t\) 循环左移一位后变成 \(t'=t_2\cdots t_m t_1\) 也是 \(s\) 的一个子串。
  对于 \(10\%\) 的数据 \(|s|\le 200\),对于 \(40\%\) 的数据 \(|s|\le 5000\),对于 \(100\%\) 的数据,\(|s|\le 3\times 10^5\)

题解

  看到“本质不同”就知道是 SAM 模板题了……
  本来因为题太板子不想写 \(\text{sol}\) 的,后来一想回去后貌似会被封广二账号,于是存一下题和代码吧。

#include<bits/stdc++.h>
#define ll long long 
#define N 600010
using namespace std;
inline int read(){
    int x=0; bool f=1; char c=getchar();
    for(;!isdigit(c); c=getchar()) if(c=='-') f=0;
    for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
    if(f) return x; return 0-x;
}
char s[N]; int n,sum[N][27];
ll ans;
namespace SAM{
    int len[N],pos[N],ch[N][27],fa[N],tot,lst;
    void extend(int i, int c){
        int u=lst, v=++tot; lst=v, len[v]=len[u]+1, pos[v]=i;
        for(; u && !ch[u][c]; u=fa[u]) ch[u][c]=v;
        if(!u) fa[v]=1;
        else if(len[ch[u][c]]==len[u]+1) fa[v]=ch[u][c];
        else{
            int t=++tot, o=ch[u][c]; len[t]=len[u]+1, pos[t]=pos[o];
            memcpy(ch[t],ch[o],sizeof ch[o]);
            fa[t]=fa[o], fa[o]=fa[v]=t;
            for(; u && ch[u][c]==o; u=fa[u]) ch[u][c]=t;
        }
    }
    /*
    int x[N],arr[N];
    void pSort(){
        for(int i=1; i<=tot; ++i) ++x[len[i]];
        for(int i=2; i<=n; ++i) x[i]+=x[i-1];
        for(int i=1; i<=tot; ++i) arr[x[len[i]]--]=i;
    }*/
}using namespace SAM;
int main(){
    scanf("%s",s+1), n=strlen(s+1);
    lst=++tot;
    for(int i=1; i<=n; ++i) extend(i,s[i]-'a');
    //pSort();
    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\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/scx2015noip-as-php/p/11386901.html
今日推荐