标签:
连续重复子串(pku2406)
给定一个字符串 L,已知这个字符串是由某个字符串 S 重复 R 次而得到的,
求 R 的最大值。
算法分析:
做法比较简单,穷举字符串 S 的长度 k,然后判断是否满足。判断的时候,
先看字符串 L 的长度能否被 k 整除,再看 suffix(1)和 suffix(k+1)的最长公共
前缀是否等于 n-k。在询问最长公共前缀的时候, suffix(1)是固定的,所以 RMQ
问题没有必要做所有的预处理,只需求出 height 数组中的每一个数到
height[rank[1]]之间的最小值即可。整个做法的时间复杂度为 O(n)。
卡倍增……
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define N 1000001 char s[N]; int n,tong[N],t[N],t2[N],sa[N],rank[N],lcp[N]; bool cmp(int y[],int i,int k) { return ((y[sa[i-1]]==y[sa[i]])&&((sa[i-1]+k>=n?-1:y[sa[i-1]+k])==(sa[i]+k>=n?-1:y[sa[i]+k]))); } void build_sa(int range) { int *x=t,*y=t2; memset(tong,0,sizeof(int)*range); for(int i=0;i<n;++i) tong[x[i]=s[i]]++; for(int i=1;i<range;++i) tong[i]+=tong[i-1]; for(int i=n-1;i>=0;--i) sa[--tong[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(int i=n-k;i<n;++i) y[p++]=i; for(int i=0;i<n;++i) if(sa[i]>=k) y[p++]=sa[i]-k; memset(tong,0,sizeof(int)*range); for(int i=0;i<n;++i) tong[x[y[i]]]++; for(int i=1;i<range;++i) tong[i]+=tong[i-1]; for(int i=n-1;i>=0;--i) sa[--tong[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for(int i=1;i<n;++i) x[sa[i]]=cmp(y,i,k)?p-1:p++; if(p>=n) break; range=p; } } void get_lcp() { int k=0; for(int i=0;i<n;++i) rank[sa[i]]=i; for(int i=0;i<n;++i) if(rank[i]) { if(k) --k; int j=sa[rank[i]-1]; while(s[i+k]==s[j+k]) ++k; lcp[rank[i]]=k; } } int query[N]; int main() { while(1) { scanf("%s",s); if(s[0]==‘.‘) break; n=strlen(s); build_sa(128); get_lcp(); int minv=n-sa[rank[0]]; for(int i=rank[0];i>=0;--i) { query[i]=minv; minv=min(minv,lcp[i]); } minv=lcp[rank[0]+1]; for(int i=rank[0]+1;i<n;++i) { query[i]=minv; minv=min(minv,lcp[i+1]); } query[rank[n]]=0; for(int i=1;i<=n;++i) if(n%i==0&&query[rank[i]]==n-i) { printf("%d\n",n/i); break; } } return 0; }
标签:
原文地址:http://www.cnblogs.com/autsky-jadek/p/4462559.html