hihoCoder #1465 : 後綴自動機五·重複旋律8

http://hihocoder.com/problemset/problem/1465ios

 

求S的循環同構串在T中的出現次數ui

將串S變成SSspa

枚舉SS的每一個位置i,求出以i結尾的SS的子串 與 T的最長公共子串 code

若長度>=|S|,說明以i結尾的S的循環同構串在T中出現過blog

假設最後匹配i到達了後綴自動機的a節點內存

沿着a的parent樹以直向上走,走到離根最近的 匹配長度>=|S|的節點b字符串

b的在parent樹中的子樹 葉子節點個數 即爲這個以i結尾的循環同構串在T中的出現次數get

 

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

#define N 1000001

char s[N<<1];

int ch[N<<1][26],tot=1;
int last=1,p,q,np,nq;
int fa[N<<1],len[N<<1];
int r[N<<1]; 

int v[N<<1];
int sa[N<<1];

int use[N<<1];

int now,now_len;
long long ans;

void extend(int c)
{
    len[np=++tot]=len[last]+1;
    for(p=last;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
    if(!p) fa[np]=1;
    else
    {
        q=ch[p][c];
        if(len[q]==len[p]+1) fa[np]=q;
        else
        {
            nq=++tot;
            fa[nq]=fa[q];
            memcpy(ch[nq],ch[q],sizeof(ch[nq]));
            fa[q]=fa[np]=nq;
            len[nq]=len[p]+1;
            for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
        }
    }
    last=np;
}

void build()
{
    scanf("%s",s+1);
    int n=strlen(s+1);
    for(int i=1;i<=n;++i) 
    {
        r[tot+1]=1;
        extend(s[i]-'a');
    }
    for(int i=1;i<=tot;++i) v[len[i]]++;
    for(int i=1;i<=n;++i) v[i]+=v[i-1];
    for(int i=1;i<=tot;++i) sa[v[len[i]]--]=i;
    for(int i=tot;i;--i) r[fa[sa[i]]]+=r[sa[i]];
}

void find(int c,int n,int tim)
{
    while(now && !ch[now][c]) now=fa[now],now_len=len[now];
    if(!now)
    {
        now=1;
        now_len=0;
    }
    else now=ch[now][c],now_len++;
    if(now_len>n)
    while(len[fa[now]]>=n) 
    {
        now=fa[now];
        now_len=len[now];
    }
    if(now_len>=n && use[now]!=tim)
    {
        use[now]=tim;
        ans+=r[now];
    }
//    printf("%d\n",ans);
}
     
void solve()
{
    int n,m,L;
    scanf("%d",&n);
    for(int t=1;t<=n;++t) 
    {
        scanf("%s",s+1);
        m=strlen(s+1);
        for(int i=1;i<m;++i) s[m+i]=s[i];
        L=2*m-1;
        now=1; now_len=0;
        ans=0;
        for(int i=1;i<=L;++i) find(s[i]-'a',m,t);
        cout<<ans<<'\n';
    }
}

int main()
{
    freopen("rotate.in","r",stdin);
    freopen("rotate.out","w",stdout);
    build();
    solve();
}
    

 

時間限制:10000ms
單點時限:1000ms
內存限制:256MB

描述

小Hi平時的一大興趣愛好就是演奏鋼琴。咱們知道一段音樂旋律能夠被表示爲一段數構成的數列。string

小Hi發現旋律能夠循環,每次把一段旋律裏面最前面一個音換到最後面就成爲了原旋律的「循環類似旋律」,還能夠對「循環類似旋律」進行相同的變換能繼續獲得原串的「循環類似旋律」。it

小Hi對此產生了濃厚的興趣,他有若干段旋律,和一部音樂做品。對於每一段旋律,他想知道有多少在音樂做品中的子串(重複便屢次計)和該旋律是「循環類似旋律」。

解題方法提示

輸入

第一行,一個由小寫字母構成的字符串S,表示一部音樂做品。字符串S長度不超過100000。

第二行,一個整數N,表示有N段旋律。接下來N行,每行包含一個由小寫字母構成的字符串str,表示一段旋律。全部旋律的長度和不超過 100000。

輸出

輸出共N行,每行一個整數,表示答案。

樣例輸入
abac
3
a
ab
ca
樣例輸出
2
2
1
相關文章
相關標籤/搜索