-
①给定字符串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对应的状态。
⑥所有出现位置查询
-
-
-
-
-
-
-
-
- #include<iostream>
- #include<cstdio>
- #include<string>
- #include<cstring>
- #include<vector>
- #include<cmath>
- #include<queue>
- #include<stack>
- #include<map>
- #include<set>
- #include<algorithm>
- using namespace std;
- const int maxn=10010;
- const int SIGMA_SIZE=26;
- struct SAM_Node
- {
- SAM_Node *par,*next[SIGMA_SIZE];
- int len;//从开始到当前位置的长度
- int id;//状态节点编号
- int pos;
- SAM_Node(){}
- SAM_Node(int ilen)
- {
- par=0;
- len=ilen;
- memset(next,0,sizeof(next));
- }
- };
- SAM_Node node[maxn<<2],*root,*last;
- int SAM_size;
- SAM_Node *newSAM_Node(int len)
- {
- node[SAM_size]=SAM_Node(len);
- node[SAM_size].id=SAM_size;
- return &node[SAM_size++];
- }
- SAM_Node *newSAM_Node(SAM_Node *p)
- {
- node[SAM_size]=*p;
- node[SAM_size].id=SAM_size;
- return &node[SAM_size++];
- }
- void SAM_init()
- {
- SAM_size=0;
- root=last=newSAM_Node(0);
- node[0].pos=0;
- }
- void SAM_add(int x,int len)
- {
- SAM_Node *p=last,*np=newSAM_Node(p->len+1);
- np->pos=len;
- last=np;
- while(p&&!p->next[x])
- {
- p->next[x]=np;
- p=p->par;
- }
- if(!p)
- {
- np->par=root;
- return;
- }
- SAM_Node *q=p->next[x];
- if(q->len==p->len+1)
- {
- np->par=q;
- return ;
- }
- SAM_Node *nq=newSAM_Node(q);
- nq->len=p->len+1;
- q->par=nq;
- np->par=nq;
- while(p&&p->next[x]==q)
- {
- p->next[x]=nq;
- p=p->par;
- }
- }
- void SAM_build(char *s)
- {
- SAM_init();
- int len=strlen(s);
- for(int i=0;i<len;i++)
- SAM_add(s[i]-'a',i+1);
- }
- int N;
- char s[maxn*2];
- int main()
- {
- scanf("%d",&N);
- while(N--)
- {
- scanf("%s",s);
- int len=strlen(s);
- for(int i=0;i<len;i++)
- s[len+i]=s[i];
- s[2*len]='\0';
- SAM_build(s);
- SAM_Node *p=root;
- for(int i=0;i<len;i++)
- {
- for(int j=0;j<SIGMA_SIZE;j++)
- if(p->next[j])
- {
- p=p->next[j];
- break;
- }
- }
- printf("%d\n",p->len-len+1);
- }
- return 0;
- }
poj1509 后缀自动机模板题
最新推荐文章于 2021-01-17 16:14:20 发布