题意:求一个字符串中重复出现两次以上且不重叠的不同字串的个数。比如aaaa中 a和aa符合要求,而aaa和aaaa不符合要求。
思路:好像标程给的是后缀数组,但我是后缀自动机过的,我们只要在后缀自动机中的每一个状态里,设l,r分别表示在这个状态中的子串集合的最左与最右位置,num表示这个状态中的子串一共出现了多少次。
因为在后缀自动机中,每一个状态代表了一类子串,(设一个状态为p)它们的长度范围是[p->par->val+1,p->val],(不妨设为left和right)则如果p->r-p->l>=p->val.则说明这个状态中的每一个字串都符合要求,所以答案要加上right-left+1,如果p->r-p->l处在left和right之间,则说明只有一部分的子串(也就是长度不大于p->r-p->l的子串)符合要求,答案要加上p->r-p->l-left+1,至于left,right和num的更新,由SAM的性质,我们可以先将SAM拓扑排序,然后自底向上更新即可。具体代码如下:
#include <iostream> #include <string.h> #include <stdio.h> #define maxn 2010 #define Smaxn 26 #define mod 2012 #define inf 21000000 using namespace std; struct node { node *par,*go[Smaxn]; int left,right; int num; int po; int val; }*root,*tail,que[maxn],*top[maxn]; int tot; char str[maxn>>1]; void add(int c,int l,int po) { node *p=tail,*np=&que[tot++]; np->val=l; np->po=po; while(p&&p->go[c]==NULL) p->go[c]=np,p=p->par; if(p==NULL) np->par=root; else { node *q=p->go[c]; if(p->val+1==q->val) np->par=q; else { node *nq=&que[tot++]; *nq=*q; nq->val=p->val+1; np->par=q->par=nq; while(p&&p->go[c]==q) p->go[c]=nq,p=p->par; } } tail=np; } int c[maxn],len; void init() { memset(que,0,sizeof(que)); tot=0; len=1; root=tail=&que[tot++]; } void solve() { memset(c,0,sizeof(c)); int i; for(i=0;i<tot;i++) c[que[i].val]++; for(i=1;i<len;i++) c[i]+=c[i-1]; for(i=0;i<tot;i++) top[--c[que[i].val]]=&que[i]; for(node *p=root;;p=p->go[str[p->val+1]-'a']) { p->num=1; p->left=p->right=p->po; if (p->val==len-1)break; } for(i=tot-1;i>=0;i--) { node *p=top[i]; if(p->left==0&&p->right==0) { p->left=p->right=p->po; } if(p->par) { node *q=p->par; q->num+=p->num; if(q->left==0||q->left>p->left) q->left=p->left; if(q->right==0||q->right<p->right) q->right=p->right; } } int ans=0; for(i=1;i<tot;i++) { if(que[i].num>1) { int ma=que[i].val,mi=que[i].par->val+1,le=que[i].right-que[i].left; if(le>=ma) ans+=(ma-mi+1); else if(le<ma&&le>=mi) { ans+=(le-mi+1); } } } printf("%d\n",ans); } int main() { while(1) { scanf("%s",str+1); int i,l=strlen(str+1); if(str[1]=='#') break; init(); for(i=1;i<=l;i++) { add(str[i]-'a',len++,i); } solve(); } return 0; }