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

时间:2019-06-18 19:52:50   收藏:0   阅读:113

时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述

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

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

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

解题方法提示

输入

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

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

输出

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

样例输入
abac
3
a
ab
ca
样例输出
2
2

 

思路:  这个题目,由于要考虑循环相似,所以我们对所有的模式串进行加倍处理,即添加相同的串到原串的最后。 

先对主串建立sam,然后模式串去主串上匹配,匹配的过程类似于spoj里面lcs和lcs2的做法,如果有这个字符的儿子,就沿着这个边走下去,否则就跳转到他的父亲,直到某个点拥有当前这个字符作为儿子,然后我们就走到这个儿子上去。  

每次统计当前匹配的一个最大长度,如果这个最大长度超过或者等原来模式串的长度,那么我们就不断向上沿着fa找到第一个a[i].len>=模式串长度,这样保证模式串一定在这个节点所代表的集合里面出现,然后答案累积上这个sz。

注意,由于会找到相同的节点,而每个节点在一个模式串匹配中也只能被用1次,所以我们需要标记已经用过的节点,用vis数组标记。 

技术图片
 1 #include<bits/stdc++.h>  
 2 using namespace std; 
 3 int const N=100000+3;  
 4 struct node{
 5     int len,fa,ch[26]; 
 6 }a[N<<2];  
 7 int n,tot,ls,sz[N<<1],num[N],sa[N<<1],vis[N<<1];  
 8 vector<int> d;  
 9 char s[N];      
10 void add(int c,int id){
11     int p=ls;  
12     int np=ls=++tot; 
13     a[np].len=a[p].len+1;  
14     sz[np]=1;  
15     for(;p&&!a[p].ch[c];p=a[p].fa) a[p].ch[c]=np;  
16     if(!p) a[np].fa=1; 
17     else {
18         int q=a[p].ch[c]; 
19         if(a[q].len==a[p].len+1) a[np].fa=q;  
20         else {
21             int nq=++tot;a[nq]=a[q];  
22             a[nq].len=a[p].len+1;  
23             a[q].fa=a[np].fa=nq;  
24             for(;p&& a[p].ch[c]==q;p=a[p].fa)      
25                 a[p].ch[c]=nq;  
26         } 
27     } 
28 }  
29 void solve(char *s){
30     int len=strlen(s),ans=0,p=1,tmp=0; 
31     d.clear();     
32     for(int i=0;i<2*len;i++) {
33         int c=s[i%len]-a;    
34         if(a[p].ch[c]) tmp++,p=a[p].ch[c];  
35         else {
36             while (p && !a[p].ch[c]) p=a[p].fa; 
37             if(!p) tmp=0,p=1; 
38             else {
39                 tmp=a[p].len+1; 
40                 p=a[p].ch[c];  
41             } 
42         }  
43         if(tmp>=len){ 
44             int x=p,t=a[p].fa;  
45             while (t && a[t].len>=len)
46                 x=t,t=a[t].fa;  
47             if(!vis[x]) ans+=sz[x],d.push_back(x);  
48             vis[x]=1;      
49         }   
50     }
51     printf("%d\n",ans);  
52     for(int i=0;i<d.size();i++) vis[d[i]]=0;  
53 }   
54 int main(){
55     tot=ls=1;  
56     scanf("%s",s);
57     int len=strlen(s);    
58     for(int i=0;s[i];i++)  
59         add(s[i]-a,i+1);    
60     for(int i=1;i<=tot;i++)  num[a[i].len]++; 
61     for(int i=1;i<=len;i++)  num[i]+=num[i-1];  
62     for(int i=1;i<=tot;i++)  sa[num[a[i].len]--]=i;  
63     for(int i=tot;i>=1;i--){
64         int x=sa[i];  
65         int f=a[x].fa; 
66         sz[f]+=sz[x];   
67     } 
68     scanf("%d",&n);  
69     while (n--){
70         scanf("%s",s);  
71         solve(s);  
72     } 
73     return 0; 
74 } 
View Code

 

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!