题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12580
【思路】
求出现次数不小于k次的最长可重复子串和最后的出现位置。
法一:
后缀数组,二分长度,划分height。时间复杂度为O(nlogn)
法二:
Hash法。构造字符串的hash函数,二分长度,求出hash(i,L)后排序,判断是否存在超过k个相同hash 值得块即可。时间为O(nlog2n).
注意划分height一定要精确且如果m=1需要特判(对于该模板来说)。
【代码1】
1 //193ms 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 const int maxn = 80000+10; 8 9 int s[maxn]; 10 int sa[maxn],c[maxn],t[maxn],t2[maxn]; 11 void build_sa(int m,int n) { 12 int i,*x=t,*y=t2; 13 for(i=0;i<m;i++) c[i]=0; 14 for(i=0;i<n;i++) c[x[i]=s[i]]++; 15 for(i=1;i<m;i++) c[i]+=c[i-1]; 16 for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i; 17 for(int k=1;k<=n;k<<=1) { 18 int p=0; 19 for(i=n-k;i<n;i++) y[p++]=i; 20 for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; 21 for(i=0;i<m;i++) c[i]=0; 22 for(i=0;i<n;i++) c[x[y[i]]]++; 23 for(i=0;i<m;i++) c[i]+=c[i-1]; 24 for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; 25 swap(x,y); 26 p=1; x[sa[0]]=0; 27 for(i=1;i<n;i++) 28 x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++; 29 if(p>=n) break; 30 m=p; 31 } 32 } 33 int rank[maxn],height[maxn]; 34 void getHeight(int n) { 35 int i,j,k=0; 36 for(i=0;i<=n;i++) rank[sa[i]]=i; 37 for(i=0;i<n;i++) { 38 if(k) k--; 39 j=sa[rank[i]-1]; 40 while(s[j+k]==s[i+k]) k++; 41 height[rank[i]]=k; 42 } 43 } 44 int limit,n,pos; 45 bool can(int L) { //一定要注意划分height数组的准确性 46 pos=-1; 47 int cnt=1,mx=sa[1]; 48 for(int i=2;i<=n;i++) { 49 mx=max(mx,sa[i]); 50 if(height[i]<L) cnt=1,mx=sa[i]; 51 else { 52 if(++cnt>=limit) pos=max(pos,mx); 53 } 54 } 55 return pos>=0; 56 } 57 58 char expr[maxn]; 59 int main() { 60 //freopen("in.in","r",stdin); 61 //freopen("out.out","w",stdout); 62 while(scanf("%d",&limit)==1 && limit) { 63 scanf("%s",expr); 64 n=strlen(expr); 65 for(int i=0;i<n;i++) s[i]=expr[i]; s[n]=0; 66 67 build_sa(‘z‘+1,n+1); 68 getHeight(n); 69 70 if(limit==1) { printf("%d 0\n",n); continue; } 71 int L=1,R=n+1; 72 while(L<R) { 73 int M=L+(R-L+1)/2; 74 if(can(M)) L=M; else R=M-1; 75 } 76 if(!can(L)) printf("none\n"); 77 else printf("%d %d\n",L,pos); 78 } 79 return 0; 80 }
da
【代码2】
1 //1628ms 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 8 typedef unsigned long long ULL; 9 const int maxn = 80000+10; 10 const int x = 233; 11 12 ULL hash[maxn],xp[maxn],H[maxn]; 13 int m,n; 14 char s[maxn]; 15 16 int cmp(const int& a,const int& b) { 17 return hash[a]<hash[b] || (hash[a]==hash[b] && a<b); 18 } 19 int pos,rank[maxn]; 20 bool can(int L) { 21 pos=-1; 22 for(int i=0;i<n-L+1;i++) hash[i]=H[i]-H[i+L]*xp[L],rank[i]=i; 23 sort(rank,rank+n-L+1,cmp); 24 int cnt=0; 25 for(int i=0;i<n-L+1;i++) { 26 if(!i || hash[rank[i]]!=hash[rank[i-1]]) cnt=0; 27 if(++cnt>=m) pos=max(pos,rank[i]); 28 } 29 return pos>=0; 30 } 31 32 int main() { 33 //freopen("in.in","r",stdin); 34 //freopen("outr.out","w",stdout); 35 while(scanf("%d",&m)==1 && m) { 36 scanf("%s",s); 37 n=strlen(s); 38 39 H[n]=0,xp[0]=1; 40 for(int i=n-1;i>=0;i--) H[i]=H[i+1]*x+s[i]-‘a‘; 41 for(int i=1;i<=n;i++) xp[i]=xp[i-1]*x; 42 43 if(!can(1)) printf("none\n"); 44 else { 45 int L=1,R=n+1; 46 while(L<R) { 47 int M=L+(R-L+1)/2; 48 if(can(M)) L=M; else R=M-1; 49 } 50 can(L); 51 printf("%d %d\n",L,pos); 52 } 53 } 54 return 0; 55 }
hash
时间: 2024-11-05 09:46:06