CF 235C. Cyclical Quest(后缀自动机)

传送门

解题思路

  字符串\(a\)\(b\)中出现次数,一定后缀自动机了。对文本串\(s\)建一个后缀自动机,预处理出倍增数组和\(right\)集合。考虑统计答案,对于每个模式串,因为要求出所有同构,那么就先倍长这个串,然后扫的过程中要维护在后缀自动机上匹配了多少位\(tmp\),当\(tmp>=len\)时说明可以做出贡献,那么就找到一个现在节点的最高祖先满足\(l_x>=len\),然后把此处的\(right\)集合大小加入答案。但是这样会算重复,就要给计算过答案的每个状态打个标记,撤销时用栈。数组开小调了半天。,

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=2000005;
typedef long long LL;

int n,len,a[N],c[N],stk[N],top,f[N][22];
LL ans;
char s[N],t[N];
bool vis[N];

struct SAM{
    int fa[N],ch[N][28],l[N],siz[N],cnt,lst;
    void Insert(int c){
        int p=lst,np=++cnt; l[np]=l[p]+1; lst=cnt; siz[np]=1;
        for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
        if(!p) fa[np]=1;
        else {
            int q=ch[p][c];
            if(l[q]==l[p]+1) fa[np]=q;
            else {
                int nq=++cnt; l[nq]=l[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[nq]));
                fa[nq]=fa[q]; fa[q]=fa[np]=nq;
                for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
    }
    void solve(){
        for(int i=1;i<=cnt;i++) c[l[i]]++;
        for(int i=1;i<=cnt;i++) c[i]+=c[i-1];
        for(int i=1;i<=cnt;i++) a[c[l[i]]--]=i;
        for(int i=cnt;i;i--) siz[fa[a[i]]]+=siz[a[i]];
        for(int i=2;i<=cnt;i++){
            int p=a[i]; f[p][0]=fa[p];
            for(int j=1;j<=20;j++)
                f[p][j]=f[f[p][j-1]][j-1];
        }
    }
}sam;

int main(){
    scanf("%s%d",s+1,&n); sam.cnt=sam.lst=1; len=strlen(s+1);
    for(int i=1;i<=len;i++) sam.Insert(s[i]-'a'+1);
    sam.solve(); int now,tmp;
    for(int i=1;i<=n;i++){
        scanf("%s",t+1); len=strlen(t+1);
        for(int j=1;j<=len;j++) t[j+len]=t[j];
        now=1; ans=0; tmp=0; top=0;
        for(int j=1;j<=len*2;j++){
            if(sam.ch[now][t[j]-'a'+1]) now=sam.ch[now][t[j]-'a'+1],tmp++;
            else {  
                for(;now && !sam.ch[now][t[j]-'a'+1];now=sam.fa[now]);
                if(!now) now=1,tmp=0;
                else tmp=sam.l[now]+1,now=sam.ch[now][t[j]-'a'+1];
            }
            if(tmp>=len) {
                int zz=now;
                for(int k=20;k>=0;k--)
                    if(f[zz][k] && sam.l[f[zz][k]]>=len) zz=f[zz][k];
                if(vis[zz]) continue; vis[zz]=1; stk[++top]=zz;
                ans+=sam.siz[zz];
            }
        }
        while(top) vis[stk[top--]]=0;
        printf("%lld\n",ans); 
    }
    return 0;
}   

猜你喜欢

转载自www.cnblogs.com/sdfzsyq/p/10454989.html