hiho一下第131周 后缀自动机二·重复旋律8(循环相似子串)

后缀自动机五·重复旋律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\n",solve());
    }
    return 0;
}

 

posted @ 2017-01-24 21:17  贱人方  阅读(344)  评论(0编辑  收藏  举报