给你一个长度为n的01串,问你这个串的全部子串中,出现次数大于1的子串的出现次数,最后按照字典序输出。c++
对于这个题目,咱们显然能够用两种处理后缀的数据结构进行处理。数组
我的以为在这个题中,用后缀自动机去解决会相对来讲比较好理解。数据结构
咱们知道,在后缀自动机上的结点状态\(st\),若前一个状态经过字符\(c\)与\(st\)相连,那么结点\(st\)表示的是\(endpos\)相同的子串的集合。而该点的\(endpos\)则表明的是以\(c\)为结尾的串的出现的位置集合。所以咱们发现,对于一个结点\(st\),它的\(endpos\)集合的大小便是当前结点对应的子串的出现次数。那么显然,咱们只须要把每个状态\(st\)的\(|endpos|\)求出便可。ui
而要求\(|endpos|\),咱们只须要把\(parent\)树反向建出来,自底向上去更新子树的大小便是\(|endpos|\)。spa
最后咱们只须要在后缀自动机上贪心的根据字典序对每个子串进行搜索便可。总的时间复杂度为\(\mathcal{O}(n^2)\)code
首先大概有这样的一个性质:对于两个不相同的后缀\(u\),\(v\),若是\(lcp(u,v)\)不为\(0\),那么字符串\(u\)中长度在\([1,lcp(u,v)]\)范围内的前缀一定在\(v\)中出现过至少一次。(由于每个后缀都各不相同,而若是出现相同的前缀,那么这个前缀一定在原串出现至少\(2\)次)排序
那么咱们考虑将全部的后缀按照字典序进行排序。由于全部的后缀都按照字典序进行排序了,那么若是存在一个串,知足:\(lcp(i,i-1)\le lcp(i+1,1)\),那么$ Str[rk[i]] $ 这个串的前缀一定也在串 $ Str[rk[i+1]] $ 出现过。所以,我能够按照字典序枚举每个后缀 $ rk[i] $ ,并分别枚举长度为 $ 1 \le j \le height[i] $ 的子串,咱们发现,若是在后面的位置 $ k (i+1 \le k \le n) $ 中出现 $ height[k] \ge j $ 那么说明长度为 \(j\) 的子串也会在第 \(k\) 个后缀中出现,所以咱们只须要记录第一个不知足 $ height[k] \ge j $ 的位置 \(k\) ,那么最后的答案即为 $ k-i+1 $ 。字符串
这样的总体时间复杂度为\(\mathcal{O}(n^2)\)get
// luogu-judger-enable-o2 #include <bits/stdc++.h> #define maxn 10005 using namespace std; char str[maxn]; vector<int>res; struct SAM{ int next[maxn*2][2],fa[maxn*2],len[maxn*2]; int last,cnt; int cntA[maxn*2],A[maxn*2]; int num[maxn*2]; void clear(){ last=cnt=1; fa[1]=len[1]=0; memset(next[1],0,sizeof(next[1])); } void init(char *s){ while(*s){ Insert(*s-'0'); s++; } } void Insert(int c){ int p=last; int np=++cnt; memset(next[cnt],0,sizeof(next[cnt])); len[np]=len[p]+1; last=np; while(p&&!next[p][c]) next[p][c]=np, p=fa[p]; if(!p) fa[np]=1; else{ int q=next[p][c]; if(len[q]==len[p]+1) fa[np]=q; else{ int nq=++cnt; len[nq]=len[p]+1; memcpy(next[nq],next[q],sizeof(next[q])); fa[nq]=fa[q]; fa[np]=fa[q]=nq; while(next[p][c]==q) next[p][c]=nq, p=fa[p]; } } } void build(){ memset(cntA,0,sizeof(cntA)); memset(num,0,sizeof(num)); int n=strlen(str); for(int i=1;i<=cnt;i++) cntA[len[i]]++; for(int i=1;i<=n;i++) cntA[i]+=cntA[i-1]; for(int i=cnt;i>=1;i--) A[cntA[len[i]]--]=i; int tmp=1; for(int i=0;i<n;i++){ num[tmp=next[tmp][str[i]-'0']]=1; } for(int i=cnt;i>=1;i--){ int x=A[i]; num[fa[x]]+=num[x]; } } void dfs(int x){ if(num[x]>1&&x!=1) res.push_back(num[x]); for(int i=0;i<2;i++){ if(next[x][i]!=0) dfs(next[x][i]); } } }sam; int main() { int n; scanf("%d%s",&n,str); sam.clear(); sam.init(str); sam.build(); sam.dfs(1); for(auto it:res){ printf("%d\n",it); } return 0; }
#include <bits/stdc++.h> #define maxn 10010 using namespace std; int n,rk[maxn],sa[maxn],height[maxn],tmp[maxn],cnt[maxn]; char str[maxn]; void SA(int n,int m){ int i,j,k; n++; for(i=0;i<n+5;i++) rk[i]=sa[i]=height[i]=tmp[i]=0; for(i=0;i<m;i++) cnt[i]=0; for(i=0;i<n;i++) cnt[rk[i]=str[i]]++; for(i=1;i<m;i++) cnt[i]+=cnt[i-1]; for(i=0;i<n;i++) sa[--cnt[rk[i]]]=i; for(k=1;k<=n;k<<=1){ for(i=0;i<n;i++){ j=sa[i]-k; if(j<0) j+=n; tmp[cnt[rk[j]]++]=j; } sa[tmp[cnt[0]=0]]=j=0; for(i=1;i<n;i++){ if(rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i; sa[tmp[i]]=j; } memcpy(rk,sa,n*sizeof(int)); memcpy(sa,tmp,n*sizeof(int)); if(j>=n-1) break; } //get height[] i=0,k=0,height[0]=0; for(j=rk[0];i<n-1;i++,k++){ while(~k&&str[i]!=str[sa[j-1]+k]){ height[j]=k--; j=rk[sa[j]+1]; } } } int main() { int n; scanf("%d%s",&n,str); int len=strlen(str); SA(len,200); for(int i=2;i<=n;i++){ for(int j=height[i-1]+1;j<=height[i];j++){ int k=i; while(height[k]>=j) k++; if(k-i+1<=0) continue; printf("%d\n",k-i+1); } } return 0; }