后缀自动机五·重复旋律8
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一段音乐旋律可以被表示为一段数构成的数列。
小Hi发现旋律可以循环,每次把一段旋律里面最前面一个音换到最后面就成为了原旋律的“循环相似旋律”,还可以对“循环相似旋律”进行相同的变换能继续得到原串的“循环相似旋律”。
小Hi对此产生了浓厚的兴趣,他有若干段旋律,和一部音乐作品。对于每一段旋律,他想知道有多少在音乐作品中的子串(重复便多次计)和该旋律是“循环相似旋律”。
输入
第一行,一个由小写字母构成的字符串S,表示一部音乐作品。字符串S长度不超过100000。
第二行,一个整数N,表示有N段旋律。接下来N行,每行包含一个由小写字母构成的字符串str,表示一段旋律。所有旋律的长度和不超过 100000。
输出
输出共N行,每行一个整数,表示答案。
- 样例输入
-
abac 3 a ab ca
- 样例输出
-
2 2 1
#include <iostream> #include <cstring> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <time.h> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int N=4e6+100; const int M=1e6+5; const long long MOD = 1000000007LL; int tot,slink[2*N],trans[2*N][26],minlen[2*N],maxlen[2*N],edpts[2*N]; string str; int n,sz_end[N*2]; int containPrefix[N],ind[N],ans[2*N+10],cnt[N*2],green[2*N]; ll sum[N*2],sz_valid[N*2]; int newstate(int _maxlen,int _minlen,int* _trans,int _slink,int _green) { maxlen[++tot]=_maxlen; minlen[tot]=_minlen; slink[tot]=_slink; green[tot]=_green; if(_trans) for(int i=0; i<26; i++) trans[tot][i]=_trans[i]; return tot; } int add_char(char ch,int u) { int c=ch-'a',v=u; int z=newstate(maxlen[u]+1,-1,NULL,0,1); containPrefix[z]=1; while(v&&!trans[v][c]) { trans[v][c]=z; v=slink[v]; } if(!v) { minlen[z]=1; slink[z]=1; ind[0]++; return z; } int x=trans[v][c]; if(maxlen[v]+1==maxlen[x]) { slink[z]=x; minlen[z]=maxlen[x]+1; ind[x]++; return z; } int y=newstate(maxlen[v]+1,-1,trans[x],slink[x],0); slink[z]=slink[x]=y; ind[y]+=2; minlen[x]=minlen[z]=maxlen[y]+1; while(v&&trans[v][c]==x) { trans[v][c]=y; v=slink[v]; } minlen[y]=maxlen[slink[y]]+1; return z; } void init_dag() { for ( int i = 0; i <=tot; i++ ) { if(slink[i]>0)cnt[slink[i]]++; } } void topsort() { queue<int>q; for ( int i = 1; i <=tot; i++ ) { if ( cnt[i] == 0 ) { q.push(i); sz_valid[i] = 1; sum[i] = 0; } } while(!q.empty()) { int i=q.front(); q.pop(); if(green[i])sz_end[i]++; int j=slink[i]; sz_end[j]+=sz_end[i]; if(!(--cnt[j]))q.push(j); } } int solve() { vector<bool> visited(N*2,false); int res = 0; string t; cin>>t; int len = t.size(); for(int i = 0; i < len-1; i++) { t+= t[i]; } int len2 = len*2-1; int u,l; u = 1; l = 0; for(int i = 0; i < len2; i++) { int c = t[i] - 'a'; for(; u!=1 && trans[u][c]==0;) { u = slink[u]; l = maxlen[u]; } if(trans[u][c] >0) { u = trans[u][c]; l = l + 1; } else { u = 1; l = 0; } if(l > len) { for(; maxlen[slink[u]] >= len;) { u = slink[u]; l = maxlen[u]; } } if(l >= len && !visited[u]) { visited[u] = true; res += sz_end[u]; } } return res; } int main() { cin>>str; cin>>n; int pre=1; tot=1; int len=str.length(); for(int i=0; i<len; i++) { pre=add_char(str[i],pre); } init_dag(); topsort(); for(int i=0;i<n;i++){ printf("%d ",solve()); } return 0; }