您的位置:首页 > 其它

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。

#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');
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  后缀数组