SPOJ Problem Set (classical)687. Repeats |
Problem code: REPEATS |
A string s is called an (k,l)-repeat if s is obtained by concatenating k>=1 times some seed string t with length l>=1. For example, the string
s = abaabaabaaba
is a (4,3)-repeat with t = aba as its seed string. That is, the seed string t is 3 characters long, and the whole string s is obtained by repeating t 4 times.
Write a program for the following task: Your program is given a long string u consisting of characters ‘a’ and/or ‘b’ as input. Your program must find some (k,l)-repeat that occurs as substring within u with k as large as possible. For example, the input string
u = babbabaabaabaabab
contains the underlined (4,3)-repeat s starting at position 5. Since u contains no other contiguous substring with more than 4 repeats, your program must output the maximum k.
Input
In the first line of the input contains H- the number of test cases (H <= 20). H test cases follow. First line of each test cases is n - length of the input string (n <= 50000), The next n lines contain the input string, one character (either ‘a’ or ‘b’) per line, in order.
Output
For each test cases, you should write exactly one interger k in a line - the repeat count that is maximized.
Example
Input: 1 17 b a b b a b a a b a a b a a b a b Output: 4
http://hi.baidu.com/fhnstephen/blog/item/870da9ee3651404379f0555f.html
就拿这个当模板好了,仰慕博客主人
*/
#include<math.h>
#include<stdio.h>
using namespace std;
const int maxn=50010;
const int inf=5000000;
int w[maxn],wa[maxn],wb[maxn],wv[maxn];
int sa[maxn],rank[maxn],height[maxn];
int a[maxn],f[maxn][20],n,ft[maxn];
int cmp(int *r,int a,int b,int l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for (i=0; i<m; i++) w[i]=0;
for (i=0; i<n; i++) w[x[i]=r[i]]++;
for (i=1; i<m; i++) w[i]+=w[i-1];
for (i=n-1; i>=0; i--) sa[--w[x[i]]]=i;
for (p=1,j=1; p<n; m=p,j*=2)
{
for (p=0,i=n-j; i<n; i++) y[p++]=i;
for (i=0; i<n; i++) if (sa[i]>=j) y[p++]=sa[i]-j;
for (i=0; i<m; i++) w[i]=0;
for (i=0; i<n; i++) w[wv[i]=x[y[i]]]++;
for (i=1; i<m; i++) w[i]+=w[i-1];
for (i=n-1; i>=0; i--) sa[--w[wv[i]]]=y[i];
for (t=x,x=y,y=t,x[sa[0]]=0,p=1,i=1; i<n; i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
void cal(int *r,int *sa,int n)
{
int i,j,k=0;
for (i=1; i<=n; i++) rank[sa[i]]=i;
for (i=0; i<n; height[rank[i++]]=k)
for (k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);
return;
}
int nmin(int a,int b)
{
return a<b?a:b;
}
void rmq(int n)
{
int i,j;
for (i=1; i<=n; i++)
f[i][0]=height[i];
for (j=1; j<20; j++)
for (i=1; i+(1<<j)-1<=n; i++)
f[i][j]=nmin(f[i][j-1],f[i+(1<<j-1)][j-1]);
return;
}
int lcp(int a,int b)
{
int x=rank[a],y=rank[b];
if (x>y)
{
int t=x;
x=y;
y=t;
}
x++;
int t=ft[y-x+1];
return nmin(f[x][t],f[y-(1<<t)+1][t]);
}
int main()
{
//freopen("in.txt","r",stdin);
int i,testcase=0;
char x;
for (i=0; i<maxn; i++) ft[i]=int(double(log(i))/log(2.00));
scanf("%d/n",&testcase);
while (testcase--)
{
scanf("%d/n",&n);
for (i=0; i<n; i++)
{
scanf("%c/n",&x);
a[i]=x;
}
a[n]=0;
da(a,sa,n+1,128);
cal(a,sa,n);
rmq(n);
int k,max=0,r=0,t;
for(int l=1; l<n; l++)//枚举长度
for(int i=0; i+l<n; i+=l)
{
k=lcp(i,i+l);
r=k/l+1;//注意为什么是k/l+1
t=i-(l-k%l);
if (t>=0&&k%l!=0)
if (lcp(t,t+l)>=k) r++;
if (r>max)
max=r;
//printf("l=%d r=%d i=%d i+l=%d/n",l,r,i,i+l);
}
printf("%d/n",max);
}
return 0;
}