码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-03-08 23:02:25      阅读:349      评论:0      收藏:0      [点我收藏+]

标签:abc   efi   link   namespace   特殊情况   content   技术   现在   algorithm   

描述

小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一段音乐旋律可以被表示为一段数构成的数列。

小Hi发现旋律可以循环,每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以对“循环相似旋律”进行相同的变换能继续得到原串的“循环相似旋律”。

小Hi对此产生了浓厚的兴趣,他有若干段旋律,和一部音乐作品。对于每一段旋律,他想知道有多少在音乐作品中的子串(重复便多次计)和该旋律是“循环相似旋律”。

解题方法提示

输入

第一行,一个由小写字母构成的字符串S,表示一部音乐作品。字符串S长度不超过100000。

第二行,一个整数N,表示有N段旋律。接下来N行,每行包含一个由小写字母构成的字符串str,表示一段旋律。所有旋律的长度和不超过 100000。

输出

输出共N行,每行一个整数,表示答案。

Sample Input

abac
3
a
ab
ca

Sample Output

2
2
1

一个endpos只能被寻找到一次
  1 #pragma GCC optimize(2)
  2 #pragma G++ optimize(2)
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<iostream>
  7 #include<algorithm>
  8 #include<queue>
  9 
 10 #define ll long long
 11 #define N 300007
 12 using namespace std;
 13 inline int read()
 14 {
 15     int x=0,f=1;char ch=getchar();
 16     while(!isdigit(ch)){if(ch==-)f=-1;ch=getchar();}
 17     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-0;ch=getchar();}
 18     return x*f;
 19 }
 20 
 21 int n;
 22 struct sam
 23 {
 24     int cnt,last;
 25     int c[N][26],fa[N],mx[N],endpos[N];
 26     sam(){cnt=last=1;}
 27     void extend(int x)
 28     {
 29         int p=last,np=last=++cnt;mx[np]=mx[p]+1;endpos[np]=1;
 30         while(p&&!c[p][x])
 31         {
 32             c[p][x]=np;
 33             p=fa[p];
 34         }
 35         if(!p)fa[np]=1;
 36         else
 37         {
 38             int q=c[p][x];
 39             if(mx[q]==mx[p]+1)fa[np]=q;
 40             else
 41             {
 42                 int nq=++cnt;mx[nq]=mx[p]+1;
 43                 memcpy(c[nq],c[q],sizeof(c[q]));
 44                 fa[nq]=fa[q];
 45                 fa[q]=fa[np]=nq;
 46                 while(c[p][x]==q)c[p][x]=nq,p=fa[p];
 47             }
 48         }
 49     }
 50     int now=1,pre=0,du[N];queue<int>q[2];
 51     void init_endpos()
 52     {
 53         for (int i=1;i<=cnt;i++)
 54             if(fa[i])du[fa[i]]++;
 55         for (int i=1;i<=cnt;i++)
 56             if(!du[i])q[pre].push(i);
 57         while(!q[pre].empty())
 58         {
 59             while(!q[pre].empty())
 60             {
 61                 int x=q[pre].front();q[pre].pop();
 62                 endpos[fa[x]]+=endpos[x];
 63                 du[fa[x]]--;
 64                 if(!du[fa[x]])q[now].push(fa[x]);
 65             }
 66             swap(now,pre);
 67         }
 68     }
 69     int u=1,l=0;ll ans;
 70     bool flag[N];
 71     void dp(int x,int n)
 72     {
 73         while(u&&!c[u][x])u=fa[u],l=mx[u];
 74         if(!u)u=1,l=0;
 75         else u=c[u][x],l++;
 76         if(l>n)while(mx[fa[u]]>=n)u=fa[u],l=mx[u];
 77         if(l>=n&&!flag[u])
 78         {
 79             flag[u]=true;
 80             ans+=endpos[u];
 81         }
 82     }
 83     void init()
 84     {
 85         printf("%lld\n",ans);
 86         ans=0,u=1,l=0;
 87         memset(flag,0,sizeof(flag));
 88     }
 89 }sam;
 90 char s[N],T[N];
 91 
 92 int main()
 93 {
 94     scanf("%s",s+1);int len=strlen(s+1);
 95     for (int i=1;i<=len;i++)sam.extend(s[i]-a);
 96     sam.init_endpos();
 97     n=read();
 98     while(n--)
 99     {
100         scanf("%s",T+1);
101         len=strlen(T+1);
102         for (int i=1;i<=len;i++)
103             T[i+len]=T[i];
104         len=len*2-1;
105         for (int i=1;i<=len;i++)
106             sam.dp(T[i]-a,(len+1)/2);
107         sam.init();
108     }
109 }

 

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

标签:abc   efi   link   namespace   特殊情况   content   技术   现在   algorithm   

原文地址:https://www.cnblogs.com/fengzhiyuan/p/8531069.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!