poj1509 后缀自动机模板题





  1. ①给定字符串P,问P是否为T的子串。


    我们对于T建立后缀自动机。
    我们顺着后缀自动机找即可。






    ②给定一个字符串S,问他有多少个不同的子串。
    因为后缀自动机是一个有向无环图。
    我们用dp。
    dp[v]=1+dp[w];
    我们输出dp[0]-1。






    ③不同子串的总长度:
    ans[v]=d[w]+ans[w]








    ④给定字符串S,找到和它循环同构的字典序最小字符串
    将S+S构建后缀自动机,该自动机包含了和s同构短的所有字符串。
    我们找字典树最小的,长度为length(s)的路径。




    ⑤首次出现位置查询
    为了解决这一问题,我们需要预处理firstpos,找到自动机中所有状态的出现位置,即,对每个状态v我们希望找到一个位置firstpos[v],代表
    其第一次出现的位置。换句话说,我们希望预先找出每个endpos(v)中的最小元素(我们无法明确记录整个endpos集合)。
      维护这些firstpos的最简单方法是在构建自动机时一并计算,当我们创建新的状态cur时,一旦进入函数sa_extend(),就确定该值:
     firstpos(cur)=len(cur)-1(如果我们的下标从0开始)。
    当拷贝节点q时,令:
     firstpos(clone)=firstpos(q),(因为只有一个别的可能值——firstpos(cur),显然更大)。
     这样就得到了查询的答案——firstpos(t)-length(P)+1,其中t是模式串P对应的状态。






    ⑥所有出现位置查询








  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<string>  
  5. #include<cstring>  
  6. #include<vector>  
  7. #include<cmath>  
  8. #include<queue>  
  9. #include<stack>  
  10. #include<map>  
  11. #include<set>  
  12. #include<algorithm>  
  13. using namespace std;  
  14. const int maxn=10010;  
  15. const int SIGMA_SIZE=26;  
  16. struct SAM_Node  
  17. {  
  18.     SAM_Node *par,*next[SIGMA_SIZE];  
  19.     int len;//从开始到当前位置的长度  
  20.     int id;//状态节点编号  
  21.     int pos;  
  22.     SAM_Node(){}  
  23.     SAM_Node(int ilen)  
  24.     {  
  25.         par=0;  
  26.         len=ilen;  
  27.         memset(next,0,sizeof(next));  
  28.     }  
  29. };  
  30. SAM_Node node[maxn<<2],*root,*last;  
  31. int SAM_size;  
  32. SAM_Node *newSAM_Node(int len)  
  33. {  
  34.     node[SAM_size]=SAM_Node(len);  
  35.     node[SAM_size].id=SAM_size;  
  36.     return &node[SAM_size++];  
  37. }  
  38. SAM_Node *newSAM_Node(SAM_Node *p)  
  39. {  
  40.     node[SAM_size]=*p;  
  41.     node[SAM_size].id=SAM_size;  
  42.     return &node[SAM_size++];  
  43. }  
  44. void SAM_init()  
  45. {  
  46.     SAM_size=0;  
  47.     root=last=newSAM_Node(0);  
  48.     node[0].pos=0;  
  49. }  
  50. void SAM_add(int x,int len)  
  51. {  
  52.     SAM_Node *p=last,*np=newSAM_Node(p->len+1);  
  53.     np->pos=len;  
  54.     last=np;  
  55.     while(p&&!p->next[x])  
  56.     {  
  57.         p->next[x]=np;  
  58.         p=p->par;  
  59.     }  
  60.     if(!p)  
  61.     {  
  62.         np->par=root;  
  63.         return;  
  64.     }  
  65.     SAM_Node *q=p->next[x];  
  66.     if(q->len==p->len+1)  
  67.     {  
  68.         np->par=q;  
  69.         return ;  
  70.     }  
  71.     SAM_Node *nq=newSAM_Node(q);  
  72.     nq->len=p->len+1;  
  73.     q->par=nq;  
  74.     np->par=nq;  
  75.     while(p&&p->next[x]==q)  
  76.     {  
  77.         p->next[x]=nq;  
  78.         p=p->par;  
  79.     }  
  80. }  
  81. void SAM_build(char *s)  
  82. {  
  83.     SAM_init();  
  84.     int len=strlen(s);  
  85.     for(int i=0;i<len;i++)  
  86.         SAM_add(s[i]-'a',i+1);  
  87. }  
  88. int N;  
  89. char s[maxn*2];  
  90. int main()  
  91. {  
  92.     scanf("%d",&N);  
  93.     while(N--)  
  94.     {  
  95.         scanf("%s",s);  
  96.         int len=strlen(s);  
  97.         for(int i=0;i<len;i++)  
  98.             s[len+i]=s[i];  
  99.         s[2*len]='\0';  
  100.         SAM_build(s);  
  101.         SAM_Node *p=root;  
  102.         for(int i=0;i<len;i++)  
  103.         {  
  104.             for(int j=0;j<SIGMA_SIZE;j++)  
  105.                 if(p->next[j])  
  106.                 {  
  107.                     p=p->next[j];  
  108.                     break;  
  109.                 }  
  110.         }  
  111.         printf("%d\n",p->len-len+1);  
  112.     }  
  113.     return 0;  
  114. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值