• Codeforces 235C Cyclical Quest 后缀自动机


    Codeforces 235C Cyclical Quest

    题意

    给一个字符串(s)(n)个字符串(x_1,x_2,dots,x_n),问对于每个字符串(x_i),字符串(s)中有多少个子串是(x_i)的循环同构串。
    (|s|le 10^6,sum_{i=1}^{n} |x_i| le 10^6)

    分析

    (s)插入后缀自动机,设(x_i)的长度为(m),在(x_i)之后再接一个(x_i)后在后缀自动机上跑,若匹配到的长度大于等于(m),说明匹配到了一个(x_i)的循环同构串,加上当前状态的终点集合大小(即为这个循环同构串的出现次数),并且标记当前状态,防止匹配到多个相同的循环同构串重复计算答案,终点集合大小可以拓扑排序求出。

    Code

    #include<bits/stdc++.h>
    #define rep(i,x,n) for(int i=x;i<=n;i++)
    #define per(i,n,x) for(int i=n;i>=x;i--)
    #define sz(a) int(a.size())
    #define rson mid+1,r,p<<1|1
    #define pii pair<int,int>
    #define lson l,mid,p<<1
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=2e6+10;
    const ll inf=1e18;
    int T,n,m;
    char s[N];
    struct SAM{
        int last,cnt;int ch[N][26],fa[N],len[N],sz[N],sum[N],id[N],vis[N];
        int newnode(){
            ++cnt;
            for(int i=0;i<26;i++) ch[cnt][i]=0;
            return cnt;
        }
        void insert(int c){
            int p=last,np=newnode();last=np;len[np]=len[p]+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(len[q]==len[p]+1) fa[np]=q;
                else{
                    int nq=newnode();len[nq]=len[p]+1;
                    memcpy(ch[nq],ch[q],sizeof ch[q]);
                    fa[nq]=fa[q],fa[q]=fa[np]=nq;
                    for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
                }
            }
            sz[np]=1;
        }
        void init(){
            last=cnt=1;
            for(int i=0;i<26;i++) ch[cnt][i]=0;
        }
        void gao(){
            rep(i,1,cnt) sum[len[i]]++;
            rep(i,1,cnt) sum[i]+=sum[i-1];
            rep(i,1,cnt) id[sum[len[i]]--]=i;
            per(i,cnt,1) sz[fa[id[i]]]+=sz[id[i]];
        }
        int solve(){
            int m=strlen(s);
            int u=1,l=0;
            int ans=0;
            vector<int>q;
            for(int i=0;i<2*m-1;i++){
                int c=s[i%m]-'a';
                while(!ch[u][c]&&u!=1) u=fa[u],l=len[u];
                if(ch[u][c]) u=ch[u][c],l++;
                while(len[fa[u]]>=m) u=fa[u],l=len[u];
                if(l>=m&&!vis[u]){
                    ans+=sz[u];
                    vis[u]=1;
                    q.pb(u);
                }
            }
            for(int x:q) vis[x]=0;
            return ans;
        }
    }sam;
    int main(){
        scanf("%s",s+1);   
        sam.init();
        m=strlen(s+1);
        rep(i,1,m) sam.insert(s[i]-'a');
        sam.gao();
        scanf("%d",&n);
        rep(i,1,n){
            scanf("%s",s);
            printf("%d
    ",sam.solve());
        } 
        return 0;
    }
    
    
  • 相关阅读:
    vue-路由传参
    ES6模板字符串
    es6中Set和Map数据结构
    本周面试题
    var、let和const定义变量的特点
    修改this的指向
    Echarts图表插件
    ES6学习
    swiper插件学习
    每日刷题4
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13931888.html
Copyright © 2020-2023  润新知