• hihocoder1465(循环同构串在模式串中出现次数)


    传送门

    题目概要:

    给定一个模式串 (S),然后给了 (n) 个字符串,求这 (n) 个串的循环同构在 (S) 中出现次数。
    循环同构:取从左开始任意长度子串置于末尾。

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

    思路

    对循环同构的处理我们很容易想到可以把相同的子串接到末尾,这样 (T[i-n+1,i])就是T的同构。
    求某个串在模式串中出现次数不难想到ac自动机,但是由于存在循环同构的原因,复杂度最坏会达到 (O(n^2))
    我们知道对于 (SAM) 中每个状态,(endpos) 就是这个状态中的子串出现的次数。
    于是,我们先构造 (S)(SAM),并维护两个状态。(u),以 (T[i])为结尾的最长公共前缀所属状态,(l) ,最长公共前缀的长度。初始时(u=1,l=0)
    假设我们已知(T[i-1])(u,l) ,如果(trans[u][T[i]]!=0) ,那么直接令(u'=trans[u][T[i]],l'=l+1)
    如果 (trans[u][T[i]]) 不存在,我们沿着(suffix-path(u o S))找到存在的状态 (v),令 (u=trans[v][T[i]],l=maxlen[v]+1)
    若始终不存在这样的状态,说明 (T[i])(S) 中不存在,重新初始化 (u=1,l=0)
    如果 (l geq n),说明 (lcp)中含有同构,但由于同构只是 (lcp) 的后缀,此时的状态并非我们所求的状态。
    我们继续沿着后缀链接找到最后一个满足 (maxlen[v]>=n) 的状态,此时的 (endpos[v]) 即同构串出现的次数。
    最后,(T)的同构可能存在重复的情况,比如 (aa) 的同构只有 (aa) ,所以我们标记每次的最终状态(v) ,解决重复的问题。

    代码

    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3, "Ofast", "inline")
    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    const int N=1e6+5;
    const ll mod=1e9+7;
    const double eps=1e-5;
    //const double pi=acos(-1);
    
    #define ls p<<1
    #define rs p<<1|1
    int maxlen[N<<1],trans[N<<1][26],link[N<<1],tot=1,last=1;
    int siz[N<<1],vis[N<<1],deg[N<<1];
    inline void add(int id)
    {
        int cur=++tot,p;
        siz[cur]++;
        maxlen[cur]=maxlen[last]+1;
        for(p=last;p&&!trans[p][id];p=link[p]) trans[p][id]=cur;
        if(!p) link[cur]=1;
        else
        {
            int x=trans[p][id];
            if(maxlen[x]==maxlen[p]+1) link[cur]=x;
            else
            {
                int y=++tot;
                maxlen[y]=maxlen[p]+1;
                for(int i=0;i<26;i++) trans[y][i]=trans[x][i];
                link[y]=link[x];
                for(;p&&trans[p][id]==x;p=link[p]) trans[p][id]=y;
                link[cur]=link[x]=y;
            }
        }
        last=cur;
    }
    void calc()
    {
        for(int i=1;i<=tot;i++) deg[link[i]]++;
        queue<int>q;
        for(int i=1;i<=tot;i++)
            if(!deg[i]) q.push(i);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            siz[link[u]]+=siz[u];
            if(--deg[link[u]]==0) q.push(link[u]);
        }
    }
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0);
        string s;
        cin>>s;
        for(auto v:s) add(v-'a');
        calc();
        int _;
        cin>>_;
        while(_--)
        {
            cin>>s;
            int n=s.size();
            for(int i=0;i<n-1;i++) s+=s[i];
            int ans=0;
            int u=1,l=0;
            for(auto c:s)
            {
                int x=c-'a';
                while(u!=1&&!trans[u][x])
                    u=link[u],l=maxlen[u];
                if(trans[u][x])
                    u=trans[u][x],l++;
                else u=1,l=0;
                if(l>=n)
                {
                    while(maxlen[link[u]]>=n)
                        u=link[u],l=maxlen[u];
                }
                if(l>=n&&vis[u]!=_+1)
                    vis[u]=1+_,ans+=siz[u];
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    Arduino可穿戴教程Linux平台下安装Arduino IDE
    伪造服务钓鱼工具Ghost Phisher
    Xamarin开发教程如何使用Xamarin开发Android应用
    域名扫描工具Fierce
    利用DNS Zone Transfers漏洞工具dnswalk
    域名解析服务查询工具dnstracer
    FreeRTOS--API函数
    FreeRTOS中断优先级配置(重要)
    Win7 “Bluetooth设置”对话框无法打开,及无法查找到设备
    蓝牙4.0 BLE 防丢器
  • 原文地址:https://www.cnblogs.com/Suiyue-Li/p/12666172.html
Copyright © 2020-2023  润新知