zoukankan      html  css  js  c++  java
  • 后缀自动机的模板

    1 . 求不同子串的种类

    2.长度为k的字符串的个数

    3.计算所有子串的和(0-9表示)

    4.给定模式串 s , n  个匹配串 str

    求每个匹配串的循环同构能够匹配的子串总数

    学习粗http://hihocoder.com/problemset

    模板一 我主要用这个

    #include <bits/stdc++.h>
    #define LL long long
    #define P pair<int, int>
    #define lowbit(x) (x & -x)
    #define mem(a, b) memset(a, b, sizeof(a))
    #define rep(i, a, n) for (int i = a; i <= n; ++i)
    const int maxn = 1000005;
    #define mid ((l + r) >> 1)
    #define lc rt<<1
    #define rc rt<<1|1
    using namespace std;
    // __int128 read() {    __int128 x = 0, f = 1;  char c = getchar(); while (c < '0' || c > '9') {        if (c == '-') f = -1;       c = getchar();  }   while (c >= '0' && c <= '9') {      x = x * 10 + c - '0';       c = getchar();  }   return x * f;}
    // void print(__int128 x) { if (x < 0) {        putchar('-');       x = -x; }   if (x > 9)  print(x / 10);  putchar(x % 10 + '0');}
    const LL mod = 1e9 + 7;
    int len;
    struct SAM{
    
        int trans[maxn<<1][26], slink[maxn<<1], maxlen[maxn<<1];
        // 用来求endpos
        int indegree[maxn<<1], endpos[maxn<<1], rank[maxn<<1], ans[maxn<<1];
        // 计算所有子串的和(0-9表示)
        LL sum[maxn<<1];
        int last, now, root;
    
        inline void newnode (int v) {
            maxlen[++now] = v;
            mem(trans[now],0);
        }
    
        inline void extend(int c) {
            newnode(maxlen[last] + 1);
            int p = last, np = now;
            // 更新trans
            while (p && !trans[p][c]) {
                trans[p][c] = np;
                p = slink[p];
            }
            if (!p) slink[np] = root;
            else {
                int q = trans[p][c];
                if (maxlen[p] + 1 != maxlen[q]) {
                    // 将q点拆出nq,使得maxlen[p] + 1 == maxlen[q]
                    newnode(maxlen[p] + 1);
                    int nq = now;
                    memcpy(trans[nq], trans[q], sizeof(trans[q]));
                    slink[nq] = slink[q];
                    slink[q] = slink[np] = nq;
                    while (p && trans[p][c] == q) {
                        trans[p][c] = nq;
                        p = slink[p];
                    }
                }else slink[np] = q;
            }
            last = np;
            // 初始状态为可接受状态
            endpos[np] = 1;
        }
    
    
        inline void init()
        {
            root = last = now = 1;
            slink[root]=0;
            mem(trans[root],0);
        }
        // 计算所有子串的和(0-9表示)
        inline LL getSum() {
            // 拓扑排序
            for (int i = 1; i <= now; ++i) indegree[ maxlen[i] ]++;
            for (int i = 1; i <= now; ++i) indegree[i] += indegree[i-1];
            for (int i = 1; i <= now; ++i) rank[ indegree[ maxlen[i] ]-- ] = i;
            mem(endpos, 0);
            endpos[1] = 1; // 从根节点向后求有效的入度
            for (int i = 1; i <= now; ++i) {
                int x = rank[i];
                for (int j = 0; j < 10; ++j) {
                    int nex = trans[x][j];
                    if (!nex) continue;
                    endpos[nex] += endpos[x]; // 有效入度
                    LL num = (sum[x] * 10 + endpos[x] * j) % mod;
                    sum[nex] = (sum[nex] + num) % mod; // 状态转移
                }
            }
            LL ans = 0;
            for (int i = 2; i <= now; ++i) ans = (ans + sum[i]) % mod;
            return ans;
        }
        inline void getEndpos() {
            // topsort
            for (int i = 1; i <= now; ++i) indegree[ maxlen[i] ]++; // 统计相同度数的节点的个数
            for (int i = 1; i <= now; ++i) indegree[i] += indegree[i-1];  // 统计度数小于等于 i 的节点的总数
            for (int i = 1; i <= now; ++i) rank[ indegree[ maxlen[i] ]-- ] = i;  // 为每个节点编号,节点度数越大编号越靠后
            // 从下往上按照slik更新
            for (int i = now; i >= 1; --i) {
                int x = rank[i];
                endpos[slink[x]] += endpos[x];
            }
        }
    
        // 求不同的子串种类
        inline LL all () {
            LL ans = 0;
            for (int i = root+1; i <= now; ++i) {
                ans += maxlen[i] - maxlen[ slink[i] ];
            }
            return ans;
        }
        // 长度为K的字符串有多种,求出现次数最多的次数
        inline void get_Maxk() {
            getEndpos();
            for (int i = 1; i <= now; ++i) {
                ans[maxlen[i]] = max(ans[maxlen[i]], endpos[i]);
            }
            for (int i = len; i >= 1; --i) ans[i] = max(ans[i], ans[i+1]);
            for (int i = 1; i <= len; ++i) //cout << ans[i] << endl;
                printf("%d
    ", ans[i]);
        }
    
    }sam;
    
    int main()
    {
    //    int n;scanf("%d",&n);
    //    string T;
    //
    //    for(int i=0 ; i<n ; i++)
    //    {
    //
    //           string str;
    //           cin>>str;
    //           T+=str;
    //           T+=":";
    //    }
    
        string T;cin>>T;
        sam.init();
       len=T.size();
        for(int i=0 ; i<len ; i++)
        sam.extend(T[i]-'a');
        cout<<sam.all()<<endl;
    
       //- sam.all();
    }
    View Code

    模板二

     在这个模板里面没有记录minlen[st]  , 但是可以间接得知 ; 比如 minlen[st] = maxlen[silnk[st]]+1

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXL=1000005;
    const int MAXS=26;
    #define ll long long
    struct SAM
    {
        int n=0, len, st;
        //st为起始点
        //n状态总数
        //maxlen表示每个状态对应的子串中长度最大值,minlen最小值
        //trans是转移边,根节点是1,所以0代表不存在
        //slink表示绿色的suffix link
        //col表示节点颜色,col=1代表是后缀节点,=0代表不是后缀的节点
        //indeg表示对于只含有suffix link的图的度,统计endposamu用
        //endposa表示该状态对应的子串们出现的结尾位置,amu表示endpos集合的大小
        //ans表示某一长度的子串的个数
        //sam中每个状态字符串长度是连续的,要求某个状态对应的子串个数只需maxlen-minlen+1即可
        int maxlen[2*MAXL+10], minlen[2*MAXL+10], trans[2*MAXL+10][MAXS], slink[2*MAXL+10], col[2*MAXL+10], indeg[2*MAXL+10], endposamu[2*MAXL+10], ans[MAXL];
    
        int new_state(int _maxlen, int _minlen, int* _trans, int _slink)
        {
            n++;
            maxlen[n]=_maxlen;
            minlen[n]=_minlen;
            for(int i=0; i<MAXS; i++)
            {
                if(_trans==NULL)
                    trans[n][i]=0;
                else
                    trans[n][i]=_trans[i];
            }
            slink[n]=_slink;
            return n;
        }
    
        int add_char(char ch, int u)
        {
            int c=ch-'a';
            int z=new_state(maxlen[u]+1, -1, NULL, 0);
            col[z]=1;
            int v=u;
            while(v!=0&&trans[v][c]==0)
            {
                trans[v][c]=z;
                v=slink[v];
            }
            if(v==0)//最简单的情况,suffix-path(u->S)上都没有对应字符ch的转移
            {
                minlen[z]=1;
                slink[z]=1;
                indeg[1]++;
                return z;
            }
            int x=trans[v][c];
            if(maxlen[v]+1==maxlen[x])//较简单的情况,不用拆分x
            {
                minlen[z]=maxlen[x]+1;
                slink[z]=x;
                indeg[x]++;
                return z;
            }
            int y=new_state(maxlen[v]+1, -1, trans[x], slink[x]); //最复杂的情况,拆分x
            col[y]=0;
    
            minlen[x]=maxlen[y]+1;
            slink[x]=y;
            minlen[z]=maxlen[y]+1;
            slink[z]=y;
            indeg[y]+=2;
            int w=v;
            while(w!=0&&trans[w][c]==x)
            {
                trans[w][c]=y;
                w=slink[w];
            }
            minlen[y]=maxlen[slink[y]]+1;
            return z;
        }
        void init()
        {
            memset(col, 0, sizeof(col));
            memset(indeg, 0, sizeof(indeg));
            memset(maxlen, 0, sizeof(maxlen));
            memset(minlen, 0, sizeof(maxlen));
            memset(trans, 0, sizeof(maxlen));
            memset(slink, 0, sizeof(maxlen));
            memset(endposamu, 0, sizeof(endposamu));
            n=0;//多case也要清空n
            st=new_state(0, -1, NULL, 0);
        }
        void getendpos()
        {
            queue<int> que;
            for(int i=st;i<=n;i++)
            {
                if(indeg[i]==0) que.push(i);
                if(col[i]==1) endposamu[i]++;
            }
            while(!que.empty())
            {
                int pos=que.front();que.pop();
                endposamu[slink[pos]]+=endposamu[pos];
                indeg[slink[pos]]--;
                if(indeg[slink[pos]]==0) que.push(slink[pos]);
            }
        }
        void addstring(string s)
        {
            int la=st;
    
            for(int i=0 ; i<s.size() ; i++)
            la=add_char(s[i],la);
        }
        ///求长度为为k的字符串有多少种
        void klensum(string s)
        {
    /// ans[i] 得到的是长度为 i 不同字符串的个数
            getendpos();
    
            for(int i=st;i<=n;i++)
            {
                ans[maxlen[i]]=max(ans[maxlen[i]], endposamu[i]);
            }
            for(int i=s.length()-1;i>=1;i--)
            {
                ans[i]=max(ans[i], ans[i+1]);
    
            }
            for(int i=1 ; i<=s.size() ; i++)
                printf("%d
    ",ans[i]);
    
        }
        ///求不同子串的种类
       // ans=∑maxlen−minlen
        void all()
        {
            ll sum=0;
            for(int i=st ; i<=n ; i++)
            {
                sum+=maxlen[i]-maxlen[slink[i]];
            }
            printf("%lld
    ",sum);
    
        }
    }sam;
    
    int main()
    {
        sam.init();
        string str;
        cin>>str;
        sam.addstring(str);
        sam.klensum(str);
       // sam.all();
    }
    View Code

    代码的介绍:

    #include<stdio.h>
    #include<bits/stdc++.h>
    #define maxc 28
    using namespace std;
    const int maxn = 1e6 + 5;
    const int mod = 1e9 + 7;
    typedef long long ll;
    int len[maxn * 2], //最长子串的长度(该节点字串数量=len[x]-len[link[x]])
    link[maxn * 2],   //后缀链接(最短串前部减少一个字符所到达的状态)
    cnt[maxn * 2],    //被后缀连接的数
    nex[maxn * 2][maxc],  //状态转移(尾部加一个字符的下一个状态)(图)
    idx, //节点编号
    last;    //最后节点
    ll epos[maxn * 2]; // enpos数(该状态子串出现数量)
    char str[maxn];
    ll a[maxn];        //长度为i的子串出现最大次数
    
    void Iint() {    //初始化
        last = idx = 1; //1表示root起始点 空集
        link[1] = len[1] = 0;
    }
    //SAM建图
    void Extend(int c) {     //插入字符,为字符ascll码值
        int x = ++idx; //创建一个新节点x;
        len[x] = len[last] + 1; //  长度等于最后一个节点+1
        epos[x] = 1;  //接受节点子串除后缀连接还需加一
        int p;  //第一个有C转移的节点;
        for (p = last; p && !nex[p][c]; p = link[p])nex[p][c] = x;//沿着后缀连接 将所有没有字符c转移的节点直接指向新节点
        if (!p)link[x] = 1, cnt[1]++;  //全部都没有c的转移 直接将新节点后缀连接到起点
        else {
            int q = nex[p][c];    //p通过c转移到的节点
            if (len[p] + 1 == len[q])    //pq是连续的
                link[x] = q, cnt[q]++; //将新节点后缀连接指向q即可,q节点的被后缀连接数+1
            else {
                int nq = ++idx;   //不连续 需要复制一份q节点
                len[nq] = len[p] + 1;   //令nq与p连续
                link[nq] = link[q];   //因后面link[q]改变此处不加cnt
                memcpy(nex[nq], nex[q], sizeof(nex[q]));  //复制q的信息给nq
                for (; p&&nex[p][c] == q; p = link[p])
                    nex[p][c] = nq;    //沿着后缀连接 将所有通过c转移为q的改为nq
                link[q] = link[x] = nq; //将x和q后缀连接改为nq
                 cnt[nq] += 2; //  nq增加两个后缀连接
            }
        }
        last = x;  //更新最后处理的节点
    }
    void GetNpos() {    //求npos数,即该节点字串出现次数
        queue<int>q;
        for (int i = 1; i <= idx; i++)
            if (!cnt[i])q.push(i);   //将所有没被后缀连接指向的节点入队
        while (!q.empty()) {
            int x = q.front();
            q.pop();
            epos[link[x]] += epos[x]; //子串数量等于所有后缀连接指向该节点的子串数量和+是否为接受节点
            if (--cnt[link[x]] == 0)q.push(link[x]);   //当所有后缀连接指向该节点的处理完毕后再入队
        }
    }
    void GetSubNum() {    //求不相同字串数量
        ll ans = 0;
        for (int i = 2; i <= idx; i++)ans += len[i] - len[link[i]];    //一状态子串数量等于len[i]-len[link[i]]
        printf("%lld
    ",ans);
    }
    void GetSubMax() {    //求出所有长度为k的子串中出现次数最多的子串出现次数
        GetNpos();
        int n = strlen(str);
        for (int i = 1; i <= idx; i++)a[len[i]] = max(a[len[i]], epos[i]);    //长度≤k的子串中出现次数最多的子串出现次数的最小值
        for (int i = n - 1; i >= 1; i--)a[i] = max(a[i], a[i + 1]);        //求一遍后缀最大值就是答案
        for (int i = 1; i <= n; i++)printf("%lld
    ", a[i]);
    
    }
    int main() {
        //freopen("c:/input.txt","r",stdin);
        return 0;
    }
    View Code

    计算所有子串的和(0-9表示)包括前导0

    这里需要些字符串的链接技巧用“:”将每个字符串链接起来

    #include <bits/stdc++.h>
    #define LL long long
    #define P pair<int, int>
    #define lowbit(x) (x & -x)
    #define mem(a, b) memset(a, b, sizeof(a))
    #define rep(i, a, n) for (int i = a; i <= n; ++i)
    const int maxn = 1000005;
    #define mid ((l + r) >> 1)
    #define lc rt<<1
    #define rc rt<<1|1
    using namespace std;
    // __int128 read() {    __int128 x = 0, f = 1;  char c = getchar(); while (c < '0' || c > '9') {        if (c == '-') f = -1;       c = getchar();  }   while (c >= '0' && c <= '9') {      x = x * 10 + c - '0';       c = getchar();  }   return x * f;}
    // void print(__int128 x) { if (x < 0) {        putchar('-');       x = -x; }   if (x > 9)  print(x / 10);  putchar(x % 10 + '0');}
    const LL mod = 1e9 + 7;
    struct SAM{
    
        int trans[maxn<<1][26], slink[maxn<<1], maxlen[maxn<<1];
        // 用来求endpos
        int indegree[maxn<<1], endpos[maxn<<1], rank[maxn<<1], ans[maxn<<1];
        // 计算所有子串的和(0-9表示)
        LL sum[maxn<<1];
        int last, now, root, len;
    
        inline void newnode (int v) {
            maxlen[++now] = v;
        }
    
        inline void extend(int c) {
            newnode(maxlen[last] + 1);
            int p = last, np = now;
            // 更新trans
            while (p && !trans[p][c]) {
                trans[p][c] = np;
                p = slink[p];
            }
            if (!p) slink[np] = root;
            else {
                int q = trans[p][c];
                if (maxlen[p] + 1 != maxlen[q]) {
                    // 将q点拆出nq,使得maxlen[p] + 1 == maxlen[q]
                    newnode(maxlen[p] + 1);
                    int nq = now;
                    memcpy(trans[nq], trans[q], sizeof(trans[q]));
                    slink[nq] = slink[q];
                    slink[q] = slink[np] = nq;
                    while (p && trans[p][c] == q) {
                        trans[p][c] = nq;
                        p = slink[p];
                    }
                }else slink[np] = q;
            }
            last = np;
            // 初始状态为可接受状态
            endpos[np] = 1;
        }
    
        inline void build(string s) {
            // scanf("%s", s);
            len = s.size();
            root = last = now = 1;
            for (int i = 0; i < len; ++i) extend(s[i] - '0'); // extend(s[i] - '1');
        }
    
        // 计算所有子串的和(0-9表示)
        inline LL getSum() {
            // 拓扑排序
            for (int i = 1; i <= now; ++i) indegree[ maxlen[i] ]++;
            for (int i = 1; i <= now; ++i) indegree[i] += indegree[i-1];
            for (int i = 1; i <= now; ++i) rank[ indegree[ maxlen[i] ]-- ] = i;
            mem(endpos, 0);
            endpos[1] = 1; // 从根节点向后求有效的入度
            for (int i = 1; i <= now; ++i) {
                int x = rank[i];
                for (int j = 0; j < 10; ++j) {
                    int nex = trans[x][j];
                    if (!nex) continue;
                    endpos[nex] += endpos[x]; // 有效入度
                    LL num = (sum[x] * 10 + endpos[x] * j) % mod;
                    sum[nex] = (sum[nex] + num) % mod; // 状态转移
                }
            }
            LL ans = 0;
            for (int i = 2; i <= now; ++i) ans = (ans + sum[i]) % mod;
            return ans;
        }
        inline void getEndpos() {
            // topsort
            for (int i = 1; i <= now; ++i) indegree[ maxlen[i] ]++; // 统计相同度数的节点的个数
            for (int i = 1; i <= now; ++i) indegree[i] += indegree[i-1];  // 统计度数小于等于 i 的节点的总数
            for (int i = 1; i <= now; ++i) rank[ indegree[ maxlen[i] ]-- ] = i;  // 为每个节点编号,节点度数越大编号越靠后
            // 从下往上按照slik更新
            for (int i = now; i >= 1; --i) {
                int x = rank[i];
                endpos[slink[x]] += endpos[x];
            }
        }
    
        // 求不同的子串种类
        inline LL all () {
            LL ans = 0;
            for (int i = root+1; i <= now; ++i) {
                ans += maxlen[i] - maxlen[ slink[i] ];
            }
            return ans;
        }
        // 长度为K的字符串有多种,求出现次数最多的次数
        inline void get_Maxk() {
            getEndpos();
            for (int i = 1; i <= now; ++i) {
                ans[maxlen[i]] = max(ans[maxlen[i]], endpos[i]);
            }
            for (int i = len; i >= 1; --i) ans[i] = max(ans[i], ans[i+1]);
            for (int i = 1; i <= len; ++i) //cout << ans[i] << endl;
                printf("%d
    ", ans[i]);
        }
    
    }sam;
    
    int main()
    {
        int n;scanf("%d",&n);
        string T;
    
        for(int i=0 ; i<n ; i++)
        {
            
               string str;
               cin>>str;
               T+=str;
               T+=":";
        }
        
      //  string T;cin>>T;
        sam.build(T);
        cout<<sam.getSum()<<endl;
    
       //- sam.all();
    }
    View Code

     计算所以子串的和(0-9)不包括前导0

    #include <bits/stdc++.h>
    
    #define P pair<int, int>
    #define lowbit(x) (x & -x)
    #define mem(a, b) memset(a, b, sizeof(a))
    #define rep(i, a, n) for (int i = a; i <= n; ++i)
    const int maxn = 100005;
    #define mid ((l + r) >> 1)
    #define lc rt<<1
    #define rc rt<<1|1
    using namespace std;
    // __int128 read() {    __int128 x = 0, f = 1;  char c = getchar(); while (c < '0' || c > '9') {        if (c == '-') f = -1;       c = getchar();  }   while (c >= '0' && c <= '9') {      x = x * 10 + c - '0';       c = getchar();  }   return x * f;}
    // void print(__int128 x) { if (x < 0) {        putchar('-');       x = -x; }   if (x > 9)  print(x / 10);  putchar(x % 10 + '0');}
    const int mod = 2012;
    struct SAM{
    
        int trans[maxn<<1][26], slink[maxn<<1], maxlen[maxn<<1];
        // 用来求endpos
        int indegree[maxn<<1], endpos[maxn<<1], rank[maxn<<1], ans[maxn<<1];
        // 计算所有子串的和(0-9表示)
        int sum[maxn<<1];
        int last, now, root, len;
    
        inline void newnode (int v) {
            maxlen[++now] = v;
        }
    
        inline void extend(int c) {
            newnode(maxlen[last] + 1);
            int p = last, np = now;
            // 更新trans
            while (p && !trans[p][c]) {
                trans[p][c] = np;
                p = slink[p];
            }
            if (!p) slink[np] = root;
            else {
                int q = trans[p][c];
                if (maxlen[p] + 1 != maxlen[q]) {
                    // 将q点拆出nq,使得maxlen[p] + 1 == maxlen[q]
                    newnode(maxlen[p] + 1);
                    int nq = now;
                    memcpy(trans[nq], trans[q], sizeof(trans[q]));
                    slink[nq] = slink[q];
                    slink[q] = slink[np] = nq;
                    while (p && trans[p][c] == q) {
                        trans[p][c] = nq;
                        p = slink[p];
                    }
                }else slink[np] = q;
            }
            last = np;
            // 初始状态为可接受状态
            endpos[np] = 1;
        }
    
    
    
        // 计算所有子串的和(0-9表示)
        inline int getSum() {
            // 拓扑排序
            for (int i = 1; i <= now; ++i) indegree[ maxlen[i] ]++;
            for (int i = 1; i <= now; ++i) indegree[i] += indegree[i-1];
            for (int i = 1; i <= now; ++i) rank[ indegree[ maxlen[i] ]-- ] = i;
            mem(endpos, 0);
            endpos[1] = 1; // 从根节点向后求有效的入度
            for (int i = 1; i <= now; ++i) {
                int x = rank[i];
                for (int j = 0; j < 10; ++j) {
                    int nex = trans[x][j];
                    if (!nex) continue;
                    if(maxlen[x]==0&&j==0) continue;
                    endpos[nex] += endpos[x]; // 有效入度
                    endpos[nex]%=mod;
                    int num = (sum[x] * 10 + endpos[x] * j) % mod;
                    sum[nex] = (sum[nex] + num) % mod; // 状态转移
                }
            }
            int ans = 0;
            for (int i = 2; i <= now; ++i) ans = (ans + sum[i]) % mod;
            return ans;
        }
        inline void init()
        {
            mem(trans,0);mem(maxlen,0);mem(slink,0);
            mem(indegree,0);mem(sum,0);
            root=now=last=1;
        }
    
    }sam;
    char str[maxn];
    int main()
    {
        int n;
        while(~scanf("%d",&n))
        {
          sam.init();
            for(int i=1 ; i<=n;  i++)
            {
               // mem(str,0);
                scanf("%s",str);
                int len=strlen(str);
                //printf("%d
    ",len);
                for(int j=0 ; j<len ; j++)
                {
                 sam.extend(str[j]-'0');
    
                }sam.extend(10);
    
    
            }printf("%d
    ",sam.getSum());
    
        }
    
       //- sam.aint();
    }
    View Code

    给定模式串 s , n  个匹配串 str

    求每个匹配串的循环同构能够匹配的子串总数

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 200010;
    int read() {
        int ans = 0 , flag = 1;
        char ch = getchar();
        while(ch > '9' || ch < '0') {if(ch == '-') flag = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9') {ans = ans * 10 + ch - '0'; ch = getchar();}
        return ans * flag;
    }
    char s[N];
    struct SAM {
        int ch[N << 1][26] , fa[N << 1] , l[N << 1] , siz[N << 1];
        int bac[N] , T[N  << 1];
        int vis[N << 1];
        int cnt , last;
        void ins(int c) {
            int x = last , nx = ++ cnt; last = nx;
            l[nx] = l[x] + 1; siz[nx] = 1;
            for(; x && !ch[x][c] ; x = fa[x]) ch[x][c] = nx;
            if(!x) fa[nx] = 1;
            else {
                int y = ch[x][c];
                if(l[y] == l[x] + 1) fa[nx] = y;
                else {
                    int ny = ++ cnt; l[ny] = l[x] + 1;
                    memcpy(ch[ny] , ch[y] , sizeof(ch[y]));
                    fa[ny] = fa[y]; fa[y] = fa[nx] = ny;
                    for(; x && ch[x][c] == y ; x = fa[x]) ch[x][c] = ny;
                }
            }
        } 
        void insert(char *s) {
            cnt = last = 1;
            int len = strlen(s);
            for(int i = 0 ; i < len ; ++ i) ins(s[i] - 'a');
    
            for(int i = 1 ; i <= cnt ; ++ i) ++ bac[l[i]];
            for(int i = 1 ; i <= len ; ++ i) bac[i] += bac[i - 1];
            for(int i = 1 ; i <= cnt ; ++ i) T[bac[l[i]] --] = i;
            for(int i = cnt ; i ; -- i) siz[fa[T[i]]] += siz[T[i]];
        }
        void cal(char * s , int qwe) {
            int n = strlen(s) , c  , m = n * 2 - 1;
            int x = 1 , lenth = 0 , ans = 0;
            for(int i = 0 , h = 0 ; i < n * 2 - 1 ; ++ i , ++ h) {
                if(h >= n) h -= n;
                c = s[h] - 'a';
                while(x && !ch[x][c]) {x = fa[x]; lenth = l[x];}
                if(ch[x][c]) {x = ch[x][c]; ++ lenth;}
                else {x = 1; lenth = 0;}
                if(lenth > n) while(l[fa[x]] >= n) {x = fa[x]; lenth = l[x];}
                if(lenth >= n && vis[x] != qwe) {vis[x] = qwe; ans += siz[x];}
            }
            printf("%d
    " , ans);
        }
    }sam;
    int main() {
        scanf("%s" , s);
        sam.insert(s);
        int t = read();
        for(int i = 1 ; i <= t ; ++ i) {
            scanf("%s" , s);
            sam.cal(s , i);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Redis分布式锁服务(转)
    redis分布式锁(转)
    MySQL+InnoDB semi-consitent read原理及实现分析(转)
    MySQL加锁处理分析(转)
    实战经验丨PHP反序列化漏洞总结
    脚本语言丨Batch入门教程第四章:调用与传参
    福利狂欢已开启,请做好准备!
    脚本语言丨Batch入门教程第三章:逻辑判断
    WinRAR存在严重的安全漏洞影响5亿用户
    Batch入门教程丨第二章:认识变量相关概念
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/10645669.html
Copyright © 2011-2022 走看看