Description
The “repetitions” of a string S(whose length is n) is a maximum number “k” such that:
1) k is a factor of n
2) S[0..n/k-1] = S[p*(n/k)..(p+1)*(n/k)-1] for all that (1 <= p < n/k)
for example:
the repetitions of “aaaaaa”is 6.
the repetitions of “abababab”is 4.
the repetitions of “abcdef”is 1.
Now, given a string S and a number K, please tell me how many substrings of S have repetitions NOT less than K.
Input
The input consists of several instances, each one for a single line.
S K
S is a string, K is a number. Check the Description for their meanings.
S contains lowercase letters(ie 'a'..'z') only.
1 <= length of S <= 100000.
1 <= K <= length of S.
Output
For each instance, output the number of substring whose repetitions is NOT less than K.
Sample Input
abcabc 2 acmac 3
Sample Output
1 0
题意:输入字符串,k,求重复次数不小于k的子串的个数。
解题思路:枚举字串长度,遍历所有的串,根据lcp向前扩展,更新答案。
代码:
/* ***********************************************
Author :xianxingwuguan
Created Time :2014-1-29 20:43:51
File Name :4.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxn=300300;
int height[maxn],sa[maxn],rank[maxn],c[maxn],t1[maxn],t2[maxn];
void da(int *str,int n,int m)
{
int i,j,k,p,*x=t1,*y=t2;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[i]=str[i]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
for(k=1;k<=n;k<<=1)
{
p=0;
for(i=n-k;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[y[i]]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
if(p>=n)break;
m=p;
}
}
void calheight(int *str,int n)
{
int i,j,k=0;
for(i=0;i<=n;i++)rank[sa[i]]=i;
for(i=0;i<n;i++)
{
if(k)k--;
j=sa[rank[i]-1];
while(str[i+k]==str[j+k])k++;
height[rank[i]]=k;
}
// printf("sa:");for(i=0;i<=n;i++)printf("%d ",sa[i]);puts("");
// printf("rank:");for(i=0;i<=n;i++)printf("%d ",rank[i]);puts("");
// printf("height:");for(i=0;i<=n;i++)printf("%d ",height[i]);puts("");
}
int str[maxn];
char ss[maxn];
int Log[maxn];
int best[23][maxn];
void init(int n)
{
int i,j;
Log[0]=-1;
for(i=1;i<=n;i++)
Log[i]=(i&(i-1))?Log[i-1]:Log[i-1]+1;
for(i=1;i<=n;i++)best[0][i]=height[i];
for(i=1;i<=Log[n];i++)
for(j=1;j<=n;j++)
best[i][j]=min(best[i-1][j],best[i-1][j+(1<<(i-1))]);
}
int lcp(int a,int b)
{
a=rank[a];
b=rank[b];
if(a>b)swap(a,b);
a++;
int t=Log[b-a+1];
return min(best[t][a],best[t][b-(1<<t)+1]);
}
int rep[maxn];
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
int i,j,k,m,n,p;
while(~scanf("%s%d",&ss,&k))
{
n=strlen(ss);
if(k==1)
{
printf("%lld\n",(long long)n*(n+1)/2);
continue;
}
for(i=0;i<n;i++)str[i]=ss[i];
str[n]=0;
da(str,n+1,300);
calheight(str,n);
init(n);
for(i=0;i<=n;i++)rep[i]=1;
for(int L=1;L*k<=n;L++)
{
for(i=0;i<n;i+=L)
{
int t=lcp(i,i+L);
if(!t)continue;
j=0;
while(j<=i&&j<L&&str[i-j]==str[i-j+L])
{
if(t>=L&&lcp(i-j,i-j+L)>=(k-1)*L)
rep[i-j]=max(rep[i-j],t/L+1);
j++;t++;
}
}
}
int ans=0;
for(i=0;i<=n;i++)if(rep[i]>=k)ans+=rep[i]-k+1;
printf("%d\n",ans);
}
return 0;
}