后缀自动机的模板

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\n", 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\n",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\n",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\n",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\n", 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\n", 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\n",len);
            for(int j=0 ; j<len ; j++)
            {
             sam.extend(str[j]-'0');

            }sam.extend(10);


        }printf("%d\n",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\n" , 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

 

转载于:https://www.cnblogs.com/shuaihui520/p/10645669.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值