poj3693 Maximum repetition substring
2016-11-29 15:55
225 查看
Description
The repetition number of a string is defined as the maximum number R
such that the string can be partitioned into R same consecutive
substrings. For example, the repetition number of “ababab” is 3 and
“ababa” is 1.
Given a string containing lowercase letters, you are to find a
substring of it with maximum repetition number.
Input
The input consists of multiple test cases. Each test case contains
exactly one line, which gives a non-empty string consisting of
lowercase letters. The length of the string will not be greater than
100,000.
The last test case is followed by a line containing a ‘#’.
Output
For each test case, print a line containing the test case number(
beginning with 1) followed by the substring of maximum repetition
number. If there are multiple substrings of maximum repetition number,
print the lexicographically smallest one.
先枚举长度l,这样只要重复了两次以上【重复一次的答案一定是单独出现的字母,可以单独判断】,一定存在i使得i * l和(i+1) * l都包含于某个答案之中。枚举i对这两个位置向前和向后分别匹配,如果匹配的总长度为k,那么重复次数就是k/l+1【还有错开的那一个】。时间复杂度O(n/1+n/2+n/3+…+n/n)=O(nlogn)。
比较麻烦的是求字典最小的解,可以通过rank值直接得出大小关系。但是经过实验发现,用ST表处理区间最小值会TLE,直接暴力反而可以AC。
The repetition number of a string is defined as the maximum number R
such that the string can be partitioned into R same consecutive
substrings. For example, the repetition number of “ababab” is 3 and
“ababa” is 1.
Given a string containing lowercase letters, you are to find a
substring of it with maximum repetition number.
Input
The input consists of multiple test cases. Each test case contains
exactly one line, which gives a non-empty string consisting of
lowercase letters. The length of the string will not be greater than
100,000.
The last test case is followed by a line containing a ‘#’.
Output
For each test case, print a line containing the test case number(
beginning with 1) followed by the substring of maximum repetition
number. If there are multiple substrings of maximum repetition number,
print the lexicographically smallest one.
先枚举长度l,这样只要重复了两次以上【重复一次的答案一定是单独出现的字母,可以单独判断】,一定存在i使得i * l和(i+1) * l都包含于某个答案之中。枚举i对这两个位置向前和向后分别匹配,如果匹配的总长度为k,那么重复次数就是k/l+1【还有错开的那一个】。时间复杂度O(n/1+n/2+n/3+…+n/n)=O(nlogn)。
比较麻烦的是求字典最小的解,可以通过rank值直接得出大小关系。但是经过实验发现,用ST表处理区间最小值会TLE,直接暴力反而可以AC。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; char s[2][100010]; int sa[2][100010],rank[2][100010],height[2][100010],f[2][300010][20],cnt[100010],t1[100010],t2[100010],n; void make() { int i,j,k,kk,p,m,*x=t1,*y=t2; n=strlen(s[0]+1); for (i=1;i<=n;i++) s[1][i]=s[0][n-i+1]; s[1][n+1]=0; for (kk=0;kk<2;kk++) { memset(t1,0,sizeof(t1)); memset(t2,0,sizeof(t2)); m='z'; memset(cnt,0,sizeof(cnt)); for (i=1;i<=n;i++) cnt[x[i]=s[kk][i]]++; for (i=2;i<=m;i++) cnt[i]+=cnt[i-1]; for (i=n;i;i--) sa[kk][cnt[x[i]]--]=i; for (k=1;k<=n;k<<=1) { p=0; for (i=n-k+1;i<=n;i++) y[++p]=i; for (i=1;i<=n;i++) if (sa[kk][i]-k>=1) y[++p]=sa[kk][i]-k; for (i=1;i<=m;i++) cnt[i]=0; for (i=1;i<=n;i++) cnt[x[y[i]]]++; for (i=2;i<=m;i++) cnt[i]+=cnt[i-1]; for (i=n;i;i--) sa[kk][cnt[x[y[i]]]--]=y[i]; swap(x,y); p=x[sa[kk][1]]=1; for (i=2;i<=n;i++) { if (y[sa[kk][i]]!=y[sa[kk][i-1]]||y[sa[kk][i]+k]!=y[sa[kk][i-1]+k]) p++; x[sa[kk][i]]=p; } if ((m=p)>=n) break; } for (i=1;i<=n;i++) rank[kk][sa[kk][i]]=i; for (i=1,k=0;i<=n;i++) { if (k) k--; if (rank[kk][i]==1) { k=0; continue; } while (s[kk][i+k]==s[kk][sa[kk][rank[kk][i]-1]+k]) k++; height[kk][rank[kk][i]]=k; } for (i=1;i<=n;i++) f[kk][i][0]=height[kk][i]; for (k=1;(1<<k)<=n;k++) for (i=1;(i+(1<<k)-1)<=n;i++) f[kk][i][k]=min(f[kk][i][k-1],f[kk][i+(1<<k-1)][k-1]); } } int qry(int kk,int x,int y) { if (x>y) swap(x,y); x++; int k=0; while ((1<<k+1)<=y-x+1) k++; return min(f[kk][x][k],f[kk][y-(1<<k)+1][k]); } void solve(int &p,int &l) { int i,j,k,ans=1,x,y,z,p1; for (i=p=l=1;i<=n;i++) if (s[0][i]<s[0][p]) p=i; for (i=1;i<=n;i++) for (j=1;j+i<=n;j+=i) { x=qry(0,rank[0][j],rank[0][j+i]); y=qry(1,rank[1][n-j+1],rank[1][n-j-i+1]); z=(x+y-1)/i+1; for (k=p1=j-y+1;k+z*i-1<=j+i+x-1;k++) if (rank[0][k]<rank[0][p1]) p1=k; if (z>ans||(z==ans&&rank[0][p1]<rank[0][p])) { ans=z; p=p1; l=z*i; } } } int main() { int i,p,l,K=0,ans; while (scanf("%s",s[0]+1)&&s[0][1]!='#') { make(); printf("Case %d: ",++K); solve(p,l); for (i=p;i<=p+l-1;i++) putchar(s[0][i]); putchar('\n'); } }
相关文章推荐
- POJ3693:Maximum repetition substring(后缀数组+RMQ)
- poj3693 Maximum repetition substring 后缀数组+RMQ
- POJ3693 Maximum repetition substring 后缀数组
- 【poj3693】Maximum repetition substring(后缀数组+RMQ)
- 【SPOJ687&POJ3693】Maximum repetition substring(后缀数组)
- 【POJ3693】Maximum repetition substring 后缀数组恶心题
- Maximum repetition substring(poj3693,后缀数组+RMQ)
- poj3693 Maximum repetition substring
- POJ3693 Maximum repetition substring
- POJ3693 - Maximum repetition substring
- poj3693 Maximum repetition substring
- POJ3693 Maximum repetition substring 后缀数组
- 【后缀数组】poj3693 Maximum repetition substring
- [POJ3693]Maximum repetition substring(后缀数组+RMQ)
- 【poj3693】 Maximum repetition substring
- poj3693 Maximum repetition substring
- 【POJ3693】Maximum repetition substring【后缀数组】
- [POJ3693]Maximum repetition substring(后缀数组+st)
- POJ3693 Maximum repetition substring [后缀数组 ST表]
- poj3693 Maximum repetition substring